diff --git a/packages/react-aria-components/src/DateField.tsx b/packages/react-aria-components/src/DateField.tsx
index df81cb40008..8108cde8cb6 100644
--- a/packages/react-aria-components/src/DateField.tsx
+++ b/packages/react-aria-components/src/DateField.tsx
@@ -92,7 +92,7 @@ export const DateField = /*#__PURE__*/ (forwardRef as forwardRefType)(function D
+ data-invalid={state.isInvalid || undefined}
+ data-disabled={state.isDisabled || undefined} />
);
});
@@ -157,7 +158,7 @@ export const TimeField = /*#__PURE__*/ (forwardRef as forwardRefType)(function T
+ data-invalid={state.isInvalid || undefined}
+ data-disabled={state.isDisabled || undefined} />
);
});
@@ -241,7 +243,7 @@ const DateInputStandalone = forwardRef((props: DateInputProps, ref: ForwardedRef
values={[
[DateFieldStateContext, state],
[InputContext, {...inputProps, ref: inputRef}],
- [GroupContext, {...fieldProps, ref: fieldRef, isInvalid: state.isInvalid}]
+ [GroupContext, {...fieldProps, ref: fieldRef, isInvalid: state.isInvalid, isDisabled: state.isDisabled}]
]}>
@@ -261,7 +263,8 @@ const DateInputInner = forwardRef((props: DateInputProps, ref: ForwardedRef
+ isInvalid={state.isInvalid}
+ isDisabled={state.isDisabled}>
{state.segments.map((segment, i) => cloneElement(children(segment), {key: i}))}
diff --git a/packages/react-aria-components/test/DateField.test.js b/packages/react-aria-components/test/DateField.test.js
index 6f467435f4b..42605d43d64 100644
--- a/packages/react-aria-components/test/DateField.test.js
+++ b/packages/react-aria-components/test/DateField.test.js
@@ -179,11 +179,18 @@ describe('DateField', () => {
it('should support render props', () => {
let {getByRole} = render(
-
- {({isInvalid}) => (
+
+ {({isInvalid, isDisabled}) => (
<>
-
+
{segment => }
>
@@ -286,6 +293,81 @@ describe('DateField', () => {
expect(group).not.toHaveAttribute('data-invalid');
});
+ it('should support both invalid and disabled states simultaneously', () => {
+ let {getByRole} = render(
+
+
+
+ `${isInvalid ? 'invalid' : ''} ${isDisabled ? 'disabled' : ''}`
+ }>
+ {segment => }
+
+
+ );
+ let group = getByRole('group');
+ expect(group).toHaveAttribute('data-invalid');
+ expect(group).toHaveAttribute('data-disabled');
+ expect(group).toHaveClass('invalid');
+ expect(group).toHaveClass('disabled');
+ });
+
+ it('should use controlled disabled state', async () => {
+ function ControlledDisabledTest() {
+ let [isDisabled, setIsDisabled] = React.useState(false);
+ return (
+ <>
+
+
+ isDisabled ? 'disabled' : ''}>
+ {segment => }
+
+
+
+ >
+ );
+ }
+ let {getByRole} = render();
+ let group = getByRole('group');
+ expect(group).not.toHaveAttribute('data-disabled');
+ expect(group).not.toHaveClass('disabled');
+
+ let button = getByRole('button');
+ await userEvent.click(button);
+
+ expect(group).toHaveAttribute('data-disabled');
+ expect(group).toHaveClass('disabled');
+ });
+
+ it('should not validate on submit when disabled', async () => {
+ let onSubmit = jest.fn();
+ let {getByRole} = render(
+
+ );
+
+ let submitButton = getByRole('button');
+ await userEvent.click(submitButton);
+
+ let group = getByRole('group');
+ expect(group).not.toHaveAttribute('data-invalid');
+ expect(group).toHaveAttribute('data-disabled');
+ expect(onSubmit).toHaveBeenCalled();
+ });
+
it('should focus previous segment when backspacing on an empty date segment', async () => {
let {getAllByRole} = render(