diff --git a/.changeset/spicy-islands-drum.md b/.changeset/spicy-islands-drum.md
new file mode 100644
index 0000000000..4ef2e10ba1
--- /dev/null
+++ b/.changeset/spicy-islands-drum.md
@@ -0,0 +1,6 @@
+---
+"@nextui-org/date-input": patch
+"@nextui-org/date-picker": patch
+---
+
+chore(date): update errorMessageFunction story and docs for date libraries
diff --git a/apps/docs/content/components/date-input/error-message-function.ts b/apps/docs/content/components/date-input/error-message-function.ts
new file mode 100644
index 0000000000..35371af420
--- /dev/null
+++ b/apps/docs/content/components/date-input/error-message-function.ts
@@ -0,0 +1,30 @@
+const App = `import {DateInput} from "@nextui-org/react";
+import {CalendarDate, parseDate} from "@internationalized/date";
+
+export default function App() {
+ return (
+
+ {
+ if (value.isInvalid) {
+ return "Please enter a valid date.";
+ }
+ }}
+ className="max-w-xs"
+ />
+
+ );
+}`;
+
+const react = {
+ "/App.jsx": App,
+};
+
+export default {
+ ...react,
+};
diff --git a/apps/docs/content/components/date-input/index.ts b/apps/docs/content/components/date-input/index.ts
index 663e66615c..3af95ddc94 100644
--- a/apps/docs/content/components/date-input/index.ts
+++ b/apps/docs/content/components/date-input/index.ts
@@ -7,6 +7,7 @@ import labelPlacements from "./label-placements";
import description from "./description";
import startEndContent from "./start-end-content";
import errorMessage from "./error-message";
+import errorMessageFunction from "./error-message-function";
import controlled from "./controlled";
import timeZones from "./time-zones";
import granularity from "./granularity";
@@ -25,6 +26,7 @@ export const dateInputContent = {
description,
startEndContent,
errorMessage,
+ errorMessageFunction,
controlled,
timeZones,
granularity,
diff --git a/apps/docs/content/components/date-picker/error-message-function.ts b/apps/docs/content/components/date-picker/error-message-function.ts
new file mode 100644
index 0000000000..2b473c9f5d
--- /dev/null
+++ b/apps/docs/content/components/date-picker/error-message-function.ts
@@ -0,0 +1,26 @@
+const App = `import {DatePicker} from "@nextui-org/react";
+
+export default function App() {
+ return (
+
+ {
+ if (value.isInvalid) {
+ return "Please enter a valid date.";
+ }
+ }}
+ />
+
+ );
+}`;
+
+const react = {
+ "/App.jsx": App,
+};
+
+export default {
+ ...react,
+};
diff --git a/apps/docs/content/components/date-picker/index.ts b/apps/docs/content/components/date-picker/index.ts
index f46ee40879..d99bfc245f 100644
--- a/apps/docs/content/components/date-picker/index.ts
+++ b/apps/docs/content/components/date-picker/index.ts
@@ -6,6 +6,7 @@ import variants from "./variants";
import labelPlacements from "./label-placements";
import description from "./description";
import errorMessage from "./error-message";
+import errorMessageFunction from "./error-message-function";
import withMonthAndYearPickers from "./with-month-and-year-pickers";
import withTimeField from "./with-time-field";
import selectorIcon from "./selector-icon";
@@ -28,6 +29,7 @@ export const datePickerContent = {
labelPlacements,
description,
errorMessage,
+ errorMessageFunction,
withMonthAndYearPickers,
withTimeField,
selectorIcon,
diff --git a/apps/docs/content/components/date-range-picker/error-message-function.ts b/apps/docs/content/components/date-range-picker/error-message-function.ts
new file mode 100644
index 0000000000..9e8cb16eab
--- /dev/null
+++ b/apps/docs/content/components/date-range-picker/error-message-function.ts
@@ -0,0 +1,30 @@
+const App = `import {DateRangePicker} from "@nextui-org/react";
+import {parseDate} from "@internationalized/date";
+
+export default function App() {
+ return (
+ {
+ if (value.isInvalid) {
+ return "Please enter your stay duration";
+ }
+ }}
+ defaultValue={{
+ start: parseDate("2024-04-01"),
+ end: parseDate("2024-04-08"),
+ }}
+ className="max-w-xs"
+ />
+ );
+}`;
+
+const react = {
+ "/App.jsx": App,
+};
+
+export default {
+ ...react,
+};
diff --git a/apps/docs/content/components/date-range-picker/index.ts b/apps/docs/content/components/date-range-picker/index.ts
index b4496b2651..27759f8408 100644
--- a/apps/docs/content/components/date-range-picker/index.ts
+++ b/apps/docs/content/components/date-range-picker/index.ts
@@ -6,6 +6,7 @@ import variants from "./variants";
import labelPlacements from "./label-placements";
import description from "./description";
import errorMessage from "./error-message";
+import errorMessageFunction from "./error-message-function";
import withTimeField from "./with-time-field";
import selectorIcon from "./selector-icon";
import controlled from "./controlled";
@@ -28,6 +29,7 @@ export const dateRangePickerContent = {
labelPlacements,
description,
errorMessage,
+ errorMessageFunction,
withTimeField,
selectorIcon,
controlled,
diff --git a/apps/docs/content/components/time-input/error-message-function.ts b/apps/docs/content/components/time-input/error-message-function.ts
new file mode 100644
index 0000000000..b8111e5265
--- /dev/null
+++ b/apps/docs/content/components/time-input/error-message-function.ts
@@ -0,0 +1,23 @@
+const App = `import {TimeInput} from "@nextui-org/react";
+
+export default function App() {
+ return (
+ {
+ if (value.isInvalid) {
+ return "Please enter a valid time";
+ }
+ }}
+ />
+ );
+}`;
+
+const react = {
+ "/App.jsx": App,
+};
+
+export default {
+ ...react,
+};
diff --git a/apps/docs/content/components/time-input/error-message.ts b/apps/docs/content/components/time-input/error-message.ts
new file mode 100644
index 0000000000..8d60a11647
--- /dev/null
+++ b/apps/docs/content/components/time-input/error-message.ts
@@ -0,0 +1,19 @@
+const App = `import {TimeInput} from "@nextui-org/react";
+
+export default function App() {
+ return (
+
+ );
+}`;
+
+const react = {
+ "/App.jsx": App,
+};
+
+export default {
+ ...react,
+};
diff --git a/apps/docs/content/components/time-input/index.ts b/apps/docs/content/components/time-input/index.ts
index de077dbed2..9daed76c58 100644
--- a/apps/docs/content/components/time-input/index.ts
+++ b/apps/docs/content/components/time-input/index.ts
@@ -4,6 +4,8 @@ import disabled from "./disabled";
import readonly from "./read-only";
import withoutLabel from "./without-label";
import withDescription from "./with-description";
+import errorMessage from "./error-message";
+import errorMessageFunction from "./error-message-function";
import labelPlacement from "./label-placement";
import startContent from "./start-content";
import endContent from "./end-content";
@@ -23,6 +25,8 @@ export const timeInputContent = {
readonly,
withoutLabel,
withDescription,
+ errorMessage,
+ errorMessageFunction,
labelPlacement,
startContent,
endContent,
diff --git a/apps/docs/content/docs/components/date-input.mdx b/apps/docs/content/docs/components/date-input.mdx
index df9e377e38..f941ddfb07 100644
--- a/apps/docs/content/docs/components/date-input.mdx
+++ b/apps/docs/content/docs/components/date-input.mdx
@@ -84,6 +84,10 @@ You can combine the `isInvalid` and `errorMessage` properties to show an invalid
+You can also pass an error message as a function. This allows for dynamic error message handling based on the [ValidationResult]((https://github.com/adobe/react-spectrum/blob/1cacbf1d438675feb3859fee54b17e620b458d9c/packages/%40react-types/shared/src/inputs.d.ts#L44-L51)).
+
+
+
### Controlled
You can use the `value` and `onChange` properties to control the input value.
diff --git a/apps/docs/content/docs/components/date-picker.mdx b/apps/docs/content/docs/components/date-picker.mdx
index 9bfd9cc04a..8c9a510980 100644
--- a/apps/docs/content/docs/components/date-picker.mdx
+++ b/apps/docs/content/docs/components/date-picker.mdx
@@ -77,6 +77,10 @@ You can combine the `isInvalid` and `errorMessage` properties to show an invalid
+You can also pass an error message as a function. This allows for dynamic error message handling based on the [ValidationResult]((https://github.com/adobe/react-spectrum/blob/1cacbf1d438675feb3859fee54b17e620b458d9c/packages/%40react-types/shared/src/inputs.d.ts#L44-L51)).
+
+
+
### With Month and Year Pickers
diff --git a/apps/docs/content/docs/components/date-range-picker.mdx b/apps/docs/content/docs/components/date-range-picker.mdx
index 5a25613c8f..b03e2d6245 100644
--- a/apps/docs/content/docs/components/date-range-picker.mdx
+++ b/apps/docs/content/docs/components/date-range-picker.mdx
@@ -92,6 +92,10 @@ You can combine the `isInvalid` and `errorMessage` properties to show an invalid
+You can also pass an error message as a function. This allows for dynamic error message handling based on the [ValidationResult]((https://github.com/adobe/react-spectrum/blob/1cacbf1d438675feb3859fee54b17e620b458d9c/packages/%40react-types/shared/src/inputs.d.ts#L44-L51)).
+
+
+
### With Time Fields
DateRangePicker automatically includes time fields when a `CalendarDateTime` or `ZonedDateTime` object is provided as the value.
diff --git a/apps/docs/content/docs/components/time-input.mdx b/apps/docs/content/docs/components/time-input.mdx
index 1010112b7d..a6b75e0886 100644
--- a/apps/docs/content/docs/components/time-input.mdx
+++ b/apps/docs/content/docs/components/time-input.mdx
@@ -78,6 +78,17 @@ A description for the field. Provides a hint such as specific requirements for w
+### With Error Message
+
+You can combine the `isInvalid` and `errorMessage` properties to show an invalid input.
+
+
+
+You can also pass an error message as a function. This allows for dynamic error message handling based on the [ValidationResult]((https://github.com/adobe/react-spectrum/blob/1cacbf1d438675feb3859fee54b17e620b458d9c/packages/%40react-types/shared/src/inputs.d.ts#L44-L51)).
+
+
+
+
### Label Placement
The label's overall position relative to the element it is labeling.
diff --git a/packages/components/date-input/src/date-input-group.tsx b/packages/components/date-input/src/date-input-group.tsx
index cecd813fdf..998d166e47 100644
--- a/packages/components/date-input/src/date-input-group.tsx
+++ b/packages/components/date-input/src/date-input-group.tsx
@@ -1,21 +1,11 @@
import type {HTMLAttributes, ReactElement, ReactNode} from "react";
-import type {GroupDOMAttributes} from "@react-types/shared";
+import type {GroupDOMAttributes, HelpTextProps, ValidationResult} from "@react-types/shared";
import {useMemo} from "react";
import {forwardRef} from "@nextui-org/system";
import {dataAttr} from "@nextui-org/shared-utils";
-// TODO: Use HelpTextProps from "@react-types/shared"; once we upgrade react-aria packages to the latest version.
-export interface ValidationResult {
- /** Whether the input value is invalid. */
- isInvalid: boolean;
- /** The current error messages for the input if it is invalid, otherwise an empty array. */
- validationErrors: string[];
- /** The native validation details for the input. */
- validationDetails: ValidityState;
-}
-
-export interface DateInputGroupProps extends ValidationResult {
+export interface DateInputGroupProps extends ValidationResult, HelpTextProps {
children?: ReactElement | ReactElement[];
shouldLabelBeOutside?: boolean;
label?: ReactNode;
@@ -27,10 +17,6 @@ export interface DateInputGroupProps extends ValidationResult {
labelProps?: HTMLAttributes;
descriptionProps?: HTMLAttributes;
errorMessageProps?: HTMLAttributes;
- /** A description for the field. Provides a hint such as specific requirements for what to choose. */
- description?: ReactNode;
- /** An error message for the field. */
- errorMessage?: ReactNode | ((v: ValidationResult) => ReactNode);
}
export const DateInputGroup = forwardRef<"div", DateInputGroupProps>((props, ref) => {
diff --git a/packages/components/date-input/stories/date-input.stories.tsx b/packages/components/date-input/stories/date-input.stories.tsx
index 87c2b74697..af0cc936f5 100644
--- a/packages/components/date-input/stories/date-input.stories.tsx
+++ b/packages/components/date-input/stories/date-input.stories.tsx
@@ -13,6 +13,7 @@ import {
} from "@internationalized/date";
import {CalendarBoldIcon} from "@nextui-org/shared-icons";
import {useDateFormatter, I18nProvider} from "@react-aria/i18n";
+import {ValidationResult} from "@react-types/shared";
import {DateInput, DateInputProps} from "../src";
@@ -254,10 +255,25 @@ export const WithErrorMessage = {
args: {
...defaultProps,
+ isInvalid: true,
errorMessage: "Please enter a valid date",
},
};
+export const WithErrorMessageFunction = {
+ render: Template,
+
+ args: {
+ ...defaultProps,
+ isInvalid: true,
+ errorMessage: (value: ValidationResult) => {
+ if (value.isInvalid) {
+ return "Please enter a valid date";
+ }
+ },
+ },
+};
+
export const IsInvalid = {
render: Template,
diff --git a/packages/components/date-input/stories/time-input.stories.tsx b/packages/components/date-input/stories/time-input.stories.tsx
index 16f0190bf2..cdf090c8b1 100644
--- a/packages/components/date-input/stories/time-input.stories.tsx
+++ b/packages/components/date-input/stories/time-input.stories.tsx
@@ -9,6 +9,7 @@ import {
ZonedDateTime,
} from "@internationalized/date";
import {useDateFormatter} from "@react-aria/i18n";
+import {ValidationResult} from "@react-types/shared";
import {TimeInput, TimeInputProps, TimeInputValue as TimeValue} from "../src";
@@ -192,6 +193,30 @@ export const WithDescription = {
},
};
+export const WithErrorMessage = {
+ render: Template,
+
+ args: {
+ ...defaultProps,
+ isInvalid: true,
+ errorMessage: "Please enter a valid time",
+ },
+};
+
+export const WithErrorMessageFunction = {
+ render: Template,
+
+ args: {
+ ...defaultProps,
+ isInvalid: true,
+ errorMessage: (value: ValidationResult) => {
+ if (value.isInvalid) {
+ return "Please enter a valid date";
+ }
+ },
+ },
+};
+
export const LabelPlacement = {
render: LabelPlacementTemplate,
diff --git a/packages/components/date-picker/stories/date-picker.stories.tsx b/packages/components/date-picker/stories/date-picker.stories.tsx
index f121153be2..d662a5415e 100644
--- a/packages/components/date-picker/stories/date-picker.stories.tsx
+++ b/packages/components/date-picker/stories/date-picker.stories.tsx
@@ -17,6 +17,7 @@ import {I18nProvider, useDateFormatter, useLocale} from "@react-aria/i18n";
import {Button, ButtonGroup} from "@nextui-org/button";
import {Radio, RadioGroup} from "@nextui-org/radio";
import {cn} from "@nextui-org/theme";
+import {ValidationResult} from "@react-types/shared";
import {DatePicker, DatePickerProps} from "../src";
@@ -424,10 +425,25 @@ export const WithErrorMessage = {
args: {
...defaultProps,
+ isInvalid: true,
errorMessage: "Please enter a valid date",
},
};
+export const WithErrorMessageFunction = {
+ render: Template,
+
+ args: {
+ ...defaultProps,
+ isInvalid: true,
+ errorMessage: (value: ValidationResult) => {
+ if (value.isInvalid) {
+ return "Please enter a valid date";
+ }
+ },
+ },
+};
+
export const IsInvalid = {
render: Template,
diff --git a/packages/components/date-picker/stories/date-range-picker.stories.tsx b/packages/components/date-picker/stories/date-range-picker.stories.tsx
index f24d1d4385..25df66ab0c 100644
--- a/packages/components/date-picker/stories/date-range-picker.stories.tsx
+++ b/packages/components/date-picker/stories/date-range-picker.stories.tsx
@@ -13,7 +13,7 @@ import {
startOfWeek,
today,
} from "@internationalized/date";
-import {RangeValue} from "@react-types/shared";
+import {RangeValue, ValidationResult} from "@react-types/shared";
import {DateValue} from "@react-types/datepicker";
import {I18nProvider, useDateFormatter, useLocale} from "@react-aria/i18n";
import {Button, ButtonGroup} from "@nextui-org/button";
@@ -499,7 +499,22 @@ export const WithErrorMessage = {
args: {
...defaultProps,
- errorMessage: "Please enter your stay duration",
+ isInvalid: true,
+ errorMessage: "Please enter a valid date range",
+ },
+};
+
+export const WithErrorMessageFunction = {
+ render: Template,
+
+ args: {
+ ...defaultProps,
+ isInvalid: true,
+ errorMessage: (value: ValidationResult) => {
+ if (value.isInvalid) {
+ return "Please enter a valid date range";
+ }
+ },
},
};