# DateRangePicker **Category**: react **URL**: https://www.heroui.com/docs/react/migration/date-range-picker **Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/react/migration/(components)/date-range-picker.mdx > Migration guide for DateRangePicker from HeroUI v2 to v3 *** Refer to the [v3 DateRangePicker documentation](/docs/react/components/date-range-picker) for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2. ## Structure Changes In v2, `DateRangePicker` was a single self-contained component with props for label, inputs, calendar, and time fields: ```tsx import { DateRangePicker } from "@heroui/react"; export default function App() { return ( ); } ``` In v3, DateRangePicker uses a composition-first API where you compose `DateField` and `RangeCalendar` explicitly: ```tsx import { DateField, DateRangePicker, Label, RangeCalendar } from "@heroui/react"; export default function App() { return ( {(segment) => } {(segment) => } {(day) => {day}} {(date) => } ); } ``` ## Key Changes ### 1. Component Structure **v2:** Single `DateRangePicker` component with all parts (two inputs, separator, calendar, label, popover) handled internally via props **v3:** Composition-based API with `DateRangePicker`, `DateField`, `RangeCalendar`, and `Label` composed together. Two `DateField.Input` components with `slot="start"` and `slot="end"` represent the range inputs. ### 2. Composition Parts | v3 Component | Description | |-----------|-------------| | `DateRangePicker` | Root container and state owner | | `DateRangePicker.Trigger` | Button that opens the calendar popover | | `DateRangePicker.TriggerIndicator` | Calendar icon (default) or custom indicator | | `DateRangePicker.RangeSeparator` | Separator between start and end date inputs (defaults to " - ") | | `DateRangePicker.Popover` | Popover wrapper for the range calendar | | `DateField.Group` | Input group wrapper | | `DateField.InputContainer` | Container for start/end inputs and separator | | `DateField.Input slot="start"` | Start date segmented input | | `DateField.Input slot="end"` | End date segmented input | | `DateField.Segment` | Individual date segment (month, day, year) | | `DateField.Suffix` | Suffix slot for the trigger button | | `RangeCalendar` | Full range calendar component (see [RangeCalendar migration](/docs/react/migration/range-calendar)) | | `Label` | External label component | ### 3. Prop Changes | v2 Prop | v3 Equivalent | Notes | |---------|---------------|-------| | `value` | `value` | Same | | `defaultValue` | `defaultValue` | Same | | `onChange` | `onChange` | Same | | `minValue` | `minValue` | Same | | `maxValue` | `maxValue` | Same | | `isDisabled` | `isDisabled` | Same | | `isReadOnly` | `isReadOnly` | Same | | `isRequired` | `isRequired` | Same | | `isInvalid` | `isInvalid` | Same | | `isOpen` | `isOpen` | Same | | `defaultOpen` | `defaultOpen` | Same | | `onOpenChange` | `onOpenChange` | Same | | `granularity` | `granularity` | Same | | `hourCycle` | `hourCycle` | Same | | `hideTimeZone` | `hideTimeZone` | Same | | `shouldForceLeadingZeros` | `shouldForceLeadingZeros` | Same | | `allowsNonContiguousRanges` | - | Set on `RangeCalendar` directly | | `pageBehavior` | - | Set on `RangeCalendar` directly | | `label` | - | Use `Label` component | | `description` | - | Use `Description` component | | `errorMessage` | - | Use `FieldError` component | | `variant` | - | Use `DateField.Group` `variant` prop or Tailwind CSS | | `color` | - | Removed (use Tailwind CSS) | | `size` | - | Removed (use Tailwind CSS) | | `radius` | - | Removed (use Tailwind CSS) | | `labelPlacement` | - | Control layout with Tailwind CSS | | `selectorIcon` | - | Pass children to `DateRangePicker.TriggerIndicator` | | `selectorButtonPlacement` | - | Compose trigger position via `DateField.Prefix` or `DateField.Suffix` | | `visibleMonths` | - | Use `RangeCalendar` `visibleDuration` prop | | `showMonthAndYearPickers` | - | Use `RangeCalendar.YearPickerTrigger` and `RangeCalendar.YearPickerGrid` | | `calendarProps` | - | Pass props directly to `RangeCalendar` | | `popoverProps` | - | Pass props directly to `DateRangePicker.Popover` | | `selectorButtonProps` | - | Pass props directly to `DateRangePicker.Trigger` | | `timeInputProps` | - | Compose time input separately | | `calendarWidth` | - | Removed (use Tailwind CSS) | | `validate` | - | Handle validation externally | | `placeholderValue` | `placeholderValue` | Same | | `autoFocus` | `autoFocus` | Same | | `disableAnimation` | - | Removed | | `classNames` | - | Use `className` on individual components | ## Migration Examples ### Basic DateRangePicker ```tsx import { DateRangePicker } from "@heroui/react"; ``` ```tsx import { DateField, DateRangePicker, Label, RangeCalendar } from "@heroui/react"; {(segment) => } {(segment) => } {(day) => {day}} {(date) => } ``` ### Controlled State ```tsx import { useState } from "react"; import { DateRangePicker } from "@heroui/react"; import { parseDate } from "@internationalized/date"; const [value, setValue] = useState({ start: parseDate("2024-03-01"), end: parseDate("2024-03-14"), }); ``` ```tsx import { useState } from "react"; import { DateField, DateRangePicker, Label, RangeCalendar } from "@heroui/react"; import { parseDate } from "@internationalized/date"; const [value, setValue] = useState({ start: parseDate("2024-03-01"), end: parseDate("2024-03-14"), }); {(segment) => } {(segment) => } {(day) => {day}} {(date) => } ``` ### With Description and Error Message ```tsx ``` ```tsx import { DateField, DateRangePicker, Label, Description, FieldError, RangeCalendar } from "@heroui/react"; {(segment) => } {(segment) => } Select your travel period End date must be after start date {/* RangeCalendar compound components */} ``` ### Custom Selector Icon ```tsx import { Icon } from "@iconify/react"; } /> ``` ```tsx import { Icon } from "@iconify/react"; {(segment) => } {(segment) => } {/* RangeCalendar compound components */} ``` ### With Visible Months and Year Picker ```tsx ``` ```tsx {(segment) => } {(segment) => }
{(day) => {day}} {(date) => } {(day) => {day}} {(date) => }
{(year) => }
```
## Styling Changes ### v2: `classNames` Prop ```tsx ``` ### v3: Direct `className` Props ```tsx {(segment) => } {(segment) => } {/* RangeCalendar compound components */} ``` ## Component Anatomy The v3 DateRangePicker follows this structure: ``` DateRangePicker (Root) ├── Label ├── DateField.Group │ ├── DateField.InputContainer │ │ ├── DateField.Input slot="start" │ │ │ └── DateField.Segment (render prop per segment) │ │ ├── DateRangePicker.RangeSeparator │ │ └── DateField.Input slot="end" │ │ └── DateField.Segment (render prop per segment) │ └── DateField.Suffix │ └── DateRangePicker.Trigger │ └── DateRangePicker.TriggerIndicator ├── Description (optional) ├── FieldError (optional) └── DateRangePicker.Popover └── RangeCalendar (see RangeCalendar migration guide) ``` ## Summary 1. **Component Structure**: Single component → composition of `DateRangePicker`, `DateField`, `RangeCalendar`, and `Label` 2. **Dual Inputs**: Built-in start/end inputs → two `DateField.Input` with `slot="start"` and `slot="end"` 3. **Separator**: Built-in → `DateRangePicker.RangeSeparator` component 4. **Label**: `label` prop → `Label` component 5. **Description/Error**: Props → `Description` and `FieldError` components 6. **Calendar**: Built-in → compose `RangeCalendar` with its own compound components inside `DateRangePicker.Popover` 7. **Selector Icon**: `selectorIcon` prop → pass children to `DateRangePicker.TriggerIndicator` 8. **Year Picker**: `showMonthAndYearPickers` prop → use `RangeCalendar.YearPickerTrigger` and `RangeCalendar.YearPickerGrid` 9. **Styling Props Removed**: `variant`, `color`, `size`, `radius` → use Tailwind CSS or `DateField.Group` variant 10. **ClassNames Removed**: Use `className` on individual compound components