diff --git a/.changeset/notes-label-placeholder.md b/.changeset/notes-label-placeholder.md new file mode 100644 index 00000000..51260bbb --- /dev/null +++ b/.changeset/notes-label-placeholder.md @@ -0,0 +1,5 @@ +--- +"@godaddy/react": patch +--- + +Add optional `notes` prop to `Checkout` for overriding the notes-collection field's label and placeholder. Both fall back to localization (`t.general.notes` / `t.shipping.notesPlaceholder`) when omitted; pass an empty `placeholder` to render none. The override applies to the standalone notes section header and the `NotesForm` field. diff --git a/packages/react/src/components/checkout/__tests__/checkout-validation.test.tsx b/packages/react/src/components/checkout/__tests__/checkout-validation.test.tsx index d39f5c01..cdaf25c2 100644 --- a/packages/react/src/components/checkout/__tests__/checkout-validation.test.tsx +++ b/packages/react/src/components/checkout/__tests__/checkout-validation.test.tsx @@ -75,6 +75,63 @@ describe('Checkout notes UI', () => { ).not.toBeInTheDocument(); }); + it('uses the custom notes label and placeholder from the notes prop (standalone)', async () => { + renderCheckout({ + sessionOverrides: { + enableNotesCollection: true, + enableShipping: false, + enableLocalPickup: false, + }, + checkoutProps: { + notes: { label: 'Gift message', placeholder: 'Say something nice' }, + }, + }); + await waitForCheckoutReady(); + + const notes = document.querySelector( + 'textarea[name="notes"]' + ) as HTMLTextAreaElement; + expect(notes).toBeInTheDocument(); + expect(notes).toHaveAttribute('placeholder', 'Say something nice'); + expect( + screen.getByRole('heading', { name: 'Gift message' }) + ).toBeInTheDocument(); + }); + + it('renders no placeholder when notes.placeholder is an empty string', async () => { + renderCheckout({ + sessionOverrides: { + enableNotesCollection: true, + enableShipping: false, + enableLocalPickup: false, + }, + checkoutProps: { notes: { placeholder: '' } }, + }); + await waitForCheckoutReady(); + + const notes = document.querySelector( + 'textarea[name="notes"]' + ) as HTMLTextAreaElement; + expect(notes).toHaveAttribute('placeholder', ''); + }); + + it('falls back to localized notes label and placeholder without an override', async () => { + renderCheckout({ + sessionOverrides: { + enableNotesCollection: true, + enableShipping: false, + enableLocalPickup: false, + }, + }); + await waitForCheckoutReady(); + + const notes = document.querySelector( + 'textarea[name="notes"]' + ) as HTMLTextAreaElement; + expect(notes).toHaveAttribute('placeholder', 'Notes or special instructions'); + expect(screen.getByRole('heading', { name: 'Notes' })).toBeInTheDocument(); + }); + it('renders notes in both shipping and pickup flows', async () => { const { user } = renderCheckout(); await waitForCheckoutReady(); diff --git a/packages/react/src/components/checkout/checkout.tsx b/packages/react/src/components/checkout/checkout.tsx index e3efb6ff..1f785eb5 100644 --- a/packages/react/src/components/checkout/checkout.tsx +++ b/packages/react/src/components/checkout/checkout.tsx @@ -223,6 +223,15 @@ export interface CheckoutProps { defaultValues?: Pick; isLoading?: boolean; loadingFallback?: ReactNode; + /** + * Overrides for the notes-collection field (rendered when the session has + * `enableNotesCollection`). Each falls back to localization when omitted; + * pass an empty `placeholder` to render no placeholder. + */ + notes?: { + label?: string; + placeholder?: string; + }; } export function Checkout(props: CheckoutProps) { diff --git a/packages/react/src/components/checkout/form/checkout-form.tsx b/packages/react/src/components/checkout/form/checkout-form.tsx index c6045576..3a0c0679 100644 --- a/packages/react/src/components/checkout/form/checkout-form.tsx +++ b/packages/react/src/components/checkout/form/checkout-form.tsx @@ -483,7 +483,10 @@ export function CheckoutForm({ {session?.enableNotesCollection ? ( <> - + ) : null} @@ -494,8 +497,13 @@ export function CheckoutForm({ {enableStandaloneNotes ? ( - - + + ) : null} diff --git a/packages/react/src/components/checkout/notes/notes-form.tsx b/packages/react/src/components/checkout/notes/notes-form.tsx index 320877d9..54f49e61 100644 --- a/packages/react/src/components/checkout/notes/notes-form.tsx +++ b/packages/react/src/components/checkout/notes/notes-form.tsx @@ -17,7 +17,17 @@ import { useGoDaddyContext } from '@/godaddy-provider'; import { eventIds } from '@/tracking/events'; import { TrackingEventType, track } from '@/tracking/track'; -export function NotesForm() { +export interface NotesFormProps { + /** Overrides the visually-hidden field label; falls back to `t.general.notes`. */ + label?: string; + /** + * Overrides the textarea placeholder; falls back to + * `t.shipping.notesPlaceholder`. Pass an empty string for no placeholder. + */ + placeholder?: string; +} + +export function NotesForm({ label, placeholder }: NotesFormProps = {}) { const form = useFormContext(); const { t } = useGoDaddyContext(); const { isConfirmingCheckout, requiredFields } = useCheckoutContext(); @@ -78,9 +88,9 @@ export function NotesForm() { name='notes' render={({ field, fieldState }) => ( - {t.general.notes} + {label ?? t.general.notes}