diff --git a/.changeset/khaki-rules-breathe.md b/.changeset/khaki-rules-breathe.md new file mode 100644 index 00000000000..99489c91f19 --- /dev/null +++ b/.changeset/khaki-rules-breathe.md @@ -0,0 +1,7 @@ +--- +"@primer/react": patch +--- + +Use `aria-required` instead of `required` on required form elements + + diff --git a/src/TextInput/TextInput.features.stories.tsx b/src/TextInput/TextInput.features.stories.tsx index 51c9c7ef584..765c6210551 100644 --- a/src/TextInput/TextInput.features.stories.tsx +++ b/src/TextInput/TextInput.features.stories.tsx @@ -83,6 +83,15 @@ export const Large = () => ( ) +export const Required = () => ( + + + Default label + + + +) + export const WithLeadingVisual = () => ( diff --git a/src/TextInput/TextInput.tsx b/src/TextInput/TextInput.tsx index 9c6178004e3..5250f510b6e 100644 --- a/src/TextInput/TextInput.tsx +++ b/src/TextInput/TextInput.tsx @@ -78,6 +78,7 @@ const TextInput = React.forwardRef( variant: variantProp, // end deprecated props type = 'text', + required, ...inputProps }, ref, @@ -143,6 +144,7 @@ const TextInput = React.forwardRef( onFocus={handleInputFocus} onBlur={handleInputBlur} type={type} + aria-required={required ? 'true' : 'false'} {...inputProps} data-component="input" /> diff --git a/src/Textarea/Textarea.tsx b/src/Textarea/Textarea.tsx index f07e1aab840..669e595c7d5 100644 --- a/src/Textarea/Textarea.tsx +++ b/src/Textarea/Textarea.tsx @@ -92,7 +92,6 @@ const Textarea = React.forwardRef( { const input = getByRole('textbox') - expect(input.getAttribute('required')).not.toBeNull() + expect(input).toHaveAttribute('aria-required', 'true') }) it('renders with a caption', () => { diff --git a/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap b/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap index a1944410067..080ff22b479 100644 --- a/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap +++ b/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap @@ -118,6 +118,7 @@ exports[`snapshots renders a custom empty state message 1`] = ` aria-expanded={false} aria-haspopup="listbox" aria-owns="autocompleteId-listbox" + aria-required="false" autoComplete="off" className="c2" data-component="input" @@ -285,6 +286,7 @@ exports[`snapshots renders a loading state 1`] = ` aria-expanded={false} aria-haspopup="listbox" aria-owns="autocompleteId-listbox" + aria-required="false" autoComplete="off" className="c2" data-component="input" @@ -503,6 +505,7 @@ exports[`snapshots renders a menu that contains an item to add to the menu 1`] = aria-expanded={false} aria-haspopup="listbox" aria-owns="autocompleteId-listbox" + aria-required="false" autoComplete="off" className="c2" data-component="input" @@ -1273,6 +1276,7 @@ exports[`snapshots renders a multiselect input 1`] = ` aria-expanded={false} aria-haspopup="listbox" aria-owns="autocompleteId-listbox" + aria-required="false" autoComplete="off" className="c2" data-component="input" @@ -1946,6 +1950,7 @@ exports[`snapshots renders a multiselect input with selected menu items 1`] = ` aria-expanded={false} aria-haspopup="listbox" aria-owns="autocompleteId-listbox" + aria-required="false" autoComplete="off" className="c2" data-component="input" @@ -2751,6 +2756,7 @@ exports[`snapshots renders a single select input 1`] = ` aria-expanded={false} aria-haspopup="listbox" aria-owns="autocompleteId-listbox" + aria-required="false" autoComplete="off" className="c2" data-component="input" @@ -3775,6 +3781,7 @@ exports[`snapshots renders with an input value 1`] = ` aria-expanded={false} aria-haspopup="listbox" aria-owns="autocompleteId-listbox" + aria-required="false" autoComplete="off" className="c2" data-component="input" diff --git a/src/__tests__/__snapshots__/TextInput.test.tsx.snap b/src/__tests__/__snapshots__/TextInput.test.tsx.snap index e891006f9dd..63eaeab5e13 100644 --- a/src/__tests__/__snapshots__/TextInput.test.tsx.snap +++ b/src/__tests__/__snapshots__/TextInput.test.tsx.snap @@ -112,6 +112,7 @@ exports[`TextInput renders 1`] = ` onClick={[Function]} > { it('does not require the textarea by default', async () => { const {getInput} = await render() - expect(getInput()).not.toHaveAttribute('required') + expect(getInput()).toHaveAttribute('aria-required', 'false') }) it('requires the textarea when required', async () => { const {getInput} = await render() - expect(getInput()).toHaveAttribute('required') + expect(getInput()).toHaveAttribute('aria-required', 'true') }) it('does not render a placeholder by default', async () => {