Skip to content

Commit adc21f8

Browse files
authored
fix(form): skip native validation on disabled form elements (#7531)
* skip native validation on disabled form elements * add test
1 parent e624164 commit adc21f8

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

packages/@react-aria/form/src/useFormValidation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export function useFormValidation<T>(props: FormValidationProps<T>, state: FormV
2727

2828
// This is a useLayoutEffect so that it runs before the useEffect in useFormValidationState, which commits the validation change.
2929
useLayoutEffect(() => {
30-
if (validationBehavior === 'native' && ref?.current) {
30+
if (validationBehavior === 'native' && ref?.current && !ref.current.disabled) {
3131
let errorMessage = state.realtimeValidation.isInvalid ? state.realtimeValidation.validationErrors.join(' ') || 'Invalid value.' : '';
3232
ref.current.setCustomValidity(errorMessage);
3333

packages/react-aria-components/test/RadioGroup.test.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,45 @@ describe('RadioGroup', () => {
453453
expect(group).not.toHaveAttribute('data-invalid');
454454
});
455455

456+
it('supports validation errors when last radio is disabled', async () => {
457+
let {getByRole, getAllByRole, getByTestId} = render(
458+
<form data-testid="form">
459+
<RadioGroup isRequired>
460+
<Label>Test</Label>
461+
<Radio value="a">A</Radio>
462+
<Radio value="b" isDisabled>B</Radio>
463+
<FieldError />
464+
</RadioGroup>
465+
</form>
466+
);
467+
468+
let group = getByRole('radiogroup');
469+
expect(group).not.toHaveAttribute('aria-describedby');
470+
expect(group).not.toHaveAttribute('data-invalid');
471+
472+
let radios = getAllByRole('radio');
473+
for (let input of radios) {
474+
expect(input).toHaveAttribute('required');
475+
expect(input).not.toHaveAttribute('aria-required');
476+
expect(input.validity.valid).toBe(false);
477+
}
478+
479+
act(() => {getByTestId('form').checkValidity();});
480+
481+
expect(group).toHaveAttribute('aria-describedby');
482+
expect(document.getElementById(group.getAttribute('aria-describedby'))).toHaveTextContent('Constraints not satisfied');
483+
expect(group).toHaveAttribute('data-invalid');
484+
expect(document.activeElement).toBe(radios[0]);
485+
486+
await user.click(radios[0]);
487+
for (let input of radios) {
488+
expect(input.validity.valid).toBe(true);
489+
}
490+
491+
expect(group).not.toHaveAttribute('aria-describedby');
492+
expect(group).not.toHaveAttribute('data-invalid');
493+
});
494+
456495
it('should support focus events', async () => {
457496
let onBlur = jest.fn();
458497
let onFocus = jest.fn();

0 commit comments

Comments
 (0)