state.setTimeRange({
end: state.timeRange?.end as TimeValue,
start: v as TimeValue,
})
}
>
{(segment) => }
state.setTimeRange({
end: v as TimeValue,
start: state.timeRange?.start as TimeValue,
})
}
>
{(segment) => }
)}
Selected:{" "}
{state.value && state.value.start && state.value.end
? formatDate({end: state.value.end, start: state.value.start})
: "No date selected"}
>
)}
Hide timezone
Force leading zeros
);
}
```
### Form Example
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {
Button,
DateField,
DateRangePicker,
Description,
FieldError,
Form,
Label,
RangeCalendar,
} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
import {useState} from "react";
type DateRange = {
start: DateValue;
end: DateValue;
};
export function FormExample() {
const [value, setValue] = useState(null);
const [isSubmitting, setIsSubmitting] = useState(false);
const currentDate = today(getLocalTimeZone());
const isInvalid =
value != null && (value.start.compare(currentDate) < 0 || value.end.compare(value.start) < 0);
const handleSubmit = (event: React.FormEvent) => {
event.preventDefault();
if (!value || isInvalid) return;
setIsSubmitting(true);
setTimeout(() => {
setValue(null);
setIsSubmitting(false);
}, 1200);
};
return (
);
}
```
### Custom Indicator
`DateRangePicker.TriggerIndicator` renders the default `IconCalendar` when no children are provided. Pass children to replace it.
```tsx
"use client";
import {DateField, DateRangePicker, Description, Label, RangeCalendar} from "@heroui/react";
import {Icon} from "@iconify/react";
export function WithCustomIndicator() {
return (
{(segment) => }
{(segment) => }
Replace the default calendar icon by passing custom children.
{(day) => {day}}
{(date) => }
{({year}) => }
);
}
```
### Render Function
```tsx
"use client";
import {DateField, DateRangePicker, Label, RangeCalendar} from "@heroui/react";
export function RenderFunction() {
return (
}
startName="startDate"
>
{(segment) => }
{(segment) => }
{(day) => {day}}
{(date) => }
{({year}) => }
);
}
```
### International Calendar
By default, DateRangePicker displays dates using the calendar system for the user's locale. You can override this by wrapping your DateRangePicker with `I18nProvider` and setting the [Unicode calendar locale extension](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string).
The example below shows the Indian calendar system:
```tsx
"use client";
import {DateField, DateRangePicker, Label, RangeCalendar} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
import {I18nProvider} from "react-aria-components";
export function InternationalCalendar() {
const start = today(getLocalTimeZone());
return (
{(segment) => }
{(segment) => }
{(day) => {day}}
{(date) => }
{({year}) => }
);
}
```
**Note:** The `onChange` event always returns dates in the same calendar system as the `value` or `defaultValue` (Gregorian if no value is provided), regardless of the displayed locale.
For a complete list of supported calendar systems and their identifiers, see:
- [React Aria Calendar Implementations](https://react-aria.adobe.com/internationalized/date/Calendar#implementations)
- [React Aria International Calendars](https://react-aria.adobe.com/Calendar#international-calendars)
## Customization
### Tailwind CSS
```tsx
"use client";
import {DateField, DateRangePicker, Label, RangeCalendar} from "@heroui/react";
export function CustomStyles() {
return (
{(segment) => }
{(segment) => }
{(day) => (
{day}
)}
{(date) => }
);
}
```
### Global CSS
To customize DateRangePicker base classes, use `@layer components`.
```css
@layer components {
.date-range-picker {
@apply inline-flex flex-col gap-1;
}
.date-range-picker__trigger {
@apply inline-flex items-center justify-between;
}
.date-range-picker__trigger-indicator {
@apply text-muted;
}
.date-range-picker__range-separator {
@apply px-2 text-default;
}
.date-range-picker__popover {
@apply min-w-[var(--trigger-width)] p-0;
}
}
```
## Styling Reference
HeroUI follows the [BEM](https://getbem.com/) methodology to ensure component variants and states are reusable and easy to customize.
### CSS Classes
DateRangePicker uses these classes in `packages/styles/components/date-range-picker.css`:
- `.date-range-picker` - Root wrapper.
- `.date-range-picker__trigger` - Trigger part that opens the popover.
- `.date-range-picker__trigger-indicator` - Default/custom indicator slot.
- `.date-range-picker__range-separator` - Separator between start and end date inputs.
- `.date-range-picker__popover` - Popover content wrapper.
### Interactive States
DateRangePicker supports React Aria data attributes and pseudo states:
- **Open**: `[data-open="true"]` on trigger.
- **Disabled**: `[data-disabled="true"]` or `[aria-disabled="true"]` on trigger.
- **Focus visible**: `:focus-visible` or `[data-focus-visible="true"]` on trigger.
- **Hover**: `:hover` or `[data-hovered="true"]` on trigger.
## API Reference
### DateRangePicker
DateRangePicker inherits all props from React Aria [DateRangePicker](https://react-aria.adobe.com/DateRangePicker).
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `value` | `{ start: DateValue; end: DateValue } \| null` | - | Controlled selected date range value. |
| `defaultValue` | `{ start: DateValue; end: DateValue } \| null` | - | Default selected range in uncontrolled mode. |
| `onChange` | `(value: { start: DateValue; end: DateValue } \| null) => void` | - | Called when selected range changes. |
| `isOpen` | `boolean` | - | Controlled popover open state. |
| `defaultOpen` | `boolean` | `false` | Initial popover open state. |
| `onOpenChange` | `(isOpen: boolean) => void` | - | Called when popover open state changes. |
| `isDisabled` | `boolean` | `false` | Disables range selection and trigger interactions. |
| `isInvalid` | `boolean` | - | Marks the field as invalid for validation state. |
| `minValue` | `DateValue` | - | Minimum selectable date. |
| `maxValue` | `DateValue` | - | Maximum selectable date. |
| `startName` | `string` | - | Name used for the start date in HTML form submission. |
| `endName` | `string` | - | Name used for the end date in HTML form submission. |
| `children` | `ReactNode \| (values: DateRangePickerRenderProps) => ReactNode` | - | Composed content or render function. |
| `render` | `DOMRenderFunction` | - | Overrides the default DOM element with a custom render function.|
### Composition Parts
| Component | Description |
|-----------|-------------|
| `DateRangePicker.Root` | Root date range picker container and state owner. |
| `DateRangePicker.Trigger` | Trigger button, usually rendered inside `DateField.Suffix`. |
| `DateRangePicker.TriggerIndicator` | Indicator slot with default calendar icon. |
| `DateRangePicker.RangeSeparator` | Separator part between start and end date inputs. |
| `DateRangePicker.Popover` | Popover wrapper for `RangeCalendar` content. |
### Related packages
- [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/) — date types (`CalendarDate`, `CalendarDateTime`, `ZonedDateTime`) and utilities used by all date components
- [`I18nProvider`](https://react-aria.adobe.com/I18nProvider) — override locale for a subtree
- [`useLocale`](https://react-aria.adobe.com/useLocale) — read the current locale and layout direction
## Related Components
## Related Components
- **RangeCalendar**: Interactive month grid for selecting date ranges
- **Calendar**: Interactive month grid for selecting dates
- **DateField**: Date input field with labels, descriptions, and validation