Ark Logo

Date Picker

A component that allows users to select a date from a calendar.

Anatomy

To set up the date picker correctly, you'll need to understand its anatomy and how we name its parts.

Each part includes a data-part attribute to help identify them in the DOM.

Examples

Learn how to use the DatePicker component in your project. Let's take a look at the most basic example

import { DatePicker, Portal } from '@ark-ui/react'

export const Basic = () => {
  return (
    <DatePicker.Root>
      <DatePicker.Label>Label</DatePicker.Label>
      <DatePicker.Control>
        <DatePicker.Input />
        <DatePicker.Trigger>📅</DatePicker.Trigger>
        <DatePicker.ClearTrigger>Clear</DatePicker.ClearTrigger>
      </DatePicker.Control>
      <Portal>
        <DatePicker.Positioner>
          <DatePicker.Content>
            <DatePicker.YearSelect />
            <DatePicker.MonthSelect />
            <DatePicker.View view="day">
              <DatePicker.Context>
                {(datePicker) => (
                  <>
                    <DatePicker.ViewControl>
                      <DatePicker.PrevTrigger>Prev</DatePicker.PrevTrigger>
                      <DatePicker.ViewTrigger>
                        <DatePicker.RangeText />
                      </DatePicker.ViewTrigger>
                      <DatePicker.NextTrigger>Next</DatePicker.NextTrigger>
                    </DatePicker.ViewControl>
                    <DatePicker.Table>
                      <DatePicker.TableHead>
                        <DatePicker.TableRow>
                          {datePicker.weekDays.map((weekDay, id) => (
                            <DatePicker.TableHeader key={id}>
                              {weekDay.short}
                            </DatePicker.TableHeader>
                          ))}
                        </DatePicker.TableRow>
                      </DatePicker.TableHead>
                      <DatePicker.TableBody>
                        {datePicker.weeks.map((week, id) => (
                          <DatePicker.TableRow key={id}>
                            {week.map((day, id) => (
                              <DatePicker.TableCell key={id} value={day}>
                                <DatePicker.TableCellTrigger>{day.day}</DatePicker.TableCellTrigger>
                              </DatePicker.TableCell>
                            ))}
                          </DatePicker.TableRow>
                        ))}
                      </DatePicker.TableBody>
                    </DatePicker.Table>
                  </>
                )}
              </DatePicker.Context>
            </DatePicker.View>
            <DatePicker.View view="month">
              <DatePicker.Context>
                {(datePicker) => (
                  <>
                    <DatePicker.ViewControl>
                      <DatePicker.PrevTrigger>Prev</DatePicker.PrevTrigger>
                      <DatePicker.ViewTrigger>
                        <DatePicker.RangeText />
                      </DatePicker.ViewTrigger>
                      <DatePicker.NextTrigger>Next</DatePicker.NextTrigger>
                    </DatePicker.ViewControl>
                    <DatePicker.Table>
                      <DatePicker.TableBody>
                        {datePicker
                          .getMonthsGrid({ columns: 4, format: 'short' })
                          .map((months, id) => (
                            <DatePicker.TableRow key={id}>
                              {months.map((month, id) => (
                                <DatePicker.TableCell key={id} value={month.value}>
                                  <DatePicker.TableCellTrigger>
                                    {month.label}
                                  </DatePicker.TableCellTrigger>
                                </DatePicker.TableCell>
                              ))}
                            </DatePicker.TableRow>
                          ))}
                      </DatePicker.TableBody>
                    </DatePicker.Table>
                  </>
                )}
              </DatePicker.Context>
            </DatePicker.View>
            <DatePicker.View view="year">
              <DatePicker.Context>
                {(datePicker) => (
                  <>
                    <DatePicker.ViewControl>
                      <DatePicker.PrevTrigger>Prev</DatePicker.PrevTrigger>
                      <DatePicker.ViewTrigger>
                        <DatePicker.RangeText />
                      </DatePicker.ViewTrigger>
                      <DatePicker.NextTrigger>Next</DatePicker.NextTrigger>
                    </DatePicker.ViewControl>
                    <DatePicker.Table>
                      <DatePicker.TableBody>
                        {datePicker.getYearsGrid({ columns: 4 }).map((years, id) => (
                          <DatePicker.TableRow key={id}>
                            {years.map((year, id) => (
                              <DatePicker.TableCell key={id} value={year.value}>
                                <DatePicker.TableCellTrigger>
                                  {year.label}
                                </DatePicker.TableCellTrigger>
                              </DatePicker.TableCell>
                            ))}
                          </DatePicker.TableRow>
                        ))}
                      </DatePicker.TableBody>
                    </DatePicker.Table>
                  </>
                )}
              </DatePicker.Context>
            </DatePicker.View>
          </DatePicker.Content>
        </DatePicker.Positioner>
      </Portal>
    </DatePicker.Root>
  )
}

Range Selection

To create a Date Picker that allows a range selection, set the selectionMode prop to range.

import { DatePicker } from '@ark-ui/react'

export const Range = () => {
  return (
    <DatePicker.Root selectionMode="range">
      <DatePicker.Label>Label</DatePicker.Label>
      <DatePicker.Control>
        <DatePicker.Input index={0} />
        <DatePicker.Input index={1} />
        <DatePicker.Trigger>📅</DatePicker.Trigger>
        <DatePicker.ClearTrigger>Clear</DatePicker.ClearTrigger>
      </DatePicker.Control>
      <DatePicker.PresetTrigger value="last7Days">Last 7 days</DatePicker.PresetTrigger>
      <DatePicker.Positioner>
        <DatePicker.Content>
          <DatePicker.YearSelect />
          <DatePicker.MonthSelect />
          <DatePicker.View view="day">
            <DatePicker.Context>
              {(datePicker) => (
                <>
                  <DatePicker.ViewControl>
                    <DatePicker.PrevTrigger>Prev</DatePicker.PrevTrigger>
                    <DatePicker.ViewTrigger>
                      <DatePicker.RangeText />
                    </DatePicker.ViewTrigger>
                    <DatePicker.NextTrigger>Next</DatePicker.NextTrigger>
                  </DatePicker.ViewControl>
                  <DatePicker.Table>
                    <DatePicker.TableHead>
                      <DatePicker.TableRow>
                        {datePicker.weekDays.map((weekDay, id) => (
                          <DatePicker.TableHeader key={id}>{weekDay.short}</DatePicker.TableHeader>
                        ))}
                      </DatePicker.TableRow>
                    </DatePicker.TableHead>
                    <DatePicker.TableBody>
                      {datePicker.weeks.map((week, id) => (
                        <DatePicker.TableRow key={id}>
                          {week.map((day, id) => (
                            <DatePicker.TableCell key={id} value={day}>
                              <DatePicker.TableCellTrigger>{day.day}</DatePicker.TableCellTrigger>
                            </DatePicker.TableCell>
                          ))}
                        </DatePicker.TableRow>
                      ))}
                    </DatePicker.TableBody>
                  </DatePicker.Table>
                </>
              )}
            </DatePicker.Context>
          </DatePicker.View>
          <DatePicker.View view="month">
            <DatePicker.Context>
              {(datePicker) => (
                <>
                  <DatePicker.ViewControl>
                    <DatePicker.PrevTrigger>Prev</DatePicker.PrevTrigger>
                    <DatePicker.ViewTrigger>
                      <DatePicker.RangeText />
                    </DatePicker.ViewTrigger>
                    <DatePicker.NextTrigger>Next</DatePicker.NextTrigger>
                  </DatePicker.ViewControl>
                  <DatePicker.Table>
                    <DatePicker.TableBody>
                      {datePicker
                        .getMonthsGrid({ columns: 4, format: 'short' })
                        .map((months, id) => (
                          <DatePicker.TableRow key={id}>
                            {months.map((month, id) => (
                              <DatePicker.TableCell key={id} value={month.value}>
                                <DatePicker.TableCellTrigger>
                                  {month.label}
                                </DatePicker.TableCellTrigger>
                              </DatePicker.TableCell>
                            ))}
                          </DatePicker.TableRow>
                        ))}
                    </DatePicker.TableBody>
                  </DatePicker.Table>
                </>
              )}
            </DatePicker.Context>
          </DatePicker.View>
          <DatePicker.View view="year">
            <DatePicker.Context>
              {(datePicker) => (
                <>
                  <DatePicker.ViewControl>
                    <DatePicker.PrevTrigger>Prev</DatePicker.PrevTrigger>
                    <DatePicker.ViewTrigger>
                      <DatePicker.RangeText />
                    </DatePicker.ViewTrigger>
                    <DatePicker.NextTrigger>Next</DatePicker.NextTrigger>
                  </DatePicker.ViewControl>
                  <DatePicker.Table>
                    <DatePicker.TableBody>
                      {datePicker.getYearsGrid({ columns: 4 }).map((years, id) => (
                        <DatePicker.TableRow key={id}>
                          {years.map((year, id) => (
                            <DatePicker.TableCell key={id} value={year.value}>
                              <DatePicker.TableCellTrigger>
                                {year.label}
                              </DatePicker.TableCellTrigger>
                            </DatePicker.TableCell>
                          ))}
                        </DatePicker.TableRow>
                      ))}
                    </DatePicker.TableBody>
                  </DatePicker.Table>
                </>
              )}
            </DatePicker.Context>
          </DatePicker.View>
        </DatePicker.Content>
      </DatePicker.Positioner>
    </DatePicker.Root>
  )
}

Standalone Date Picker

In some cases, you might want to display a non-dismissible date picker. This can be achieved by setting the open prop to true and closeOnSelect prop to false.

Important to note that standalone date picker doesn't use the Portal, Positioner and Content components.

import { DatePicker } from '@ark-ui/react'

export const Standalone = () => {
  return (
    <DatePicker.Root open={true} closeOnSelect={false}>
      <DatePicker.Input />
      <DatePicker.View view="day">
        <DatePicker.Context>
          {(datePicker) => (
            <>
              <DatePicker.ViewControl>
                <DatePicker.PrevTrigger>Prev</DatePicker.PrevTrigger>
                <DatePicker.ViewTrigger>
                  <DatePicker.RangeText />
                </DatePicker.ViewTrigger>
                <DatePicker.NextTrigger>Next</DatePicker.NextTrigger>
              </DatePicker.ViewControl>
              <DatePicker.Table>
                <DatePicker.TableHead>
                  <DatePicker.TableRow>
                    {datePicker.weekDays.map((weekDay, id) => (
                      <DatePicker.TableHeader key={id}>{weekDay.short}</DatePicker.TableHeader>
                    ))}
                  </DatePicker.TableRow>
                </DatePicker.TableHead>
                <DatePicker.TableBody>
                  {datePicker.weeks.map((week, id) => (
                    <DatePicker.TableRow key={id}>
                      {week.map((day, id) => (
                        <DatePicker.TableCell key={id} value={day}>
                          <DatePicker.TableCellTrigger>{day.day}</DatePicker.TableCellTrigger>
                        </DatePicker.TableCell>
                      ))}
                    </DatePicker.TableRow>
                  ))}
                </DatePicker.TableBody>
              </DatePicker.Table>
            </>
          )}
        </DatePicker.Context>
      </DatePicker.View>
      <DatePicker.View view="month">
        <DatePicker.Context>
          {(datePicker) => (
            <>
              <DatePicker.ViewControl>
                <DatePicker.PrevTrigger>Prev</DatePicker.PrevTrigger>
                <DatePicker.ViewTrigger>
                  <DatePicker.RangeText />
                </DatePicker.ViewTrigger>
                <DatePicker.NextTrigger>Next</DatePicker.NextTrigger>
              </DatePicker.ViewControl>
              <DatePicker.Table>
                <DatePicker.TableBody>
                  {datePicker.getMonthsGrid({ columns: 4, format: 'short' }).map((months, id) => (
                    <DatePicker.TableRow key={id}>
                      {months.map((month, id) => (
                        <DatePicker.TableCell key={id} value={month.value}>
                          <DatePicker.TableCellTrigger>{month.label}</DatePicker.TableCellTrigger>
                        </DatePicker.TableCell>
                      ))}
                    </DatePicker.TableRow>
                  ))}
                </DatePicker.TableBody>
              </DatePicker.Table>
            </>
          )}
        </DatePicker.Context>
      </DatePicker.View>
      <DatePicker.View view="year">
        <DatePicker.Context>
          {(datePicker) => (
            <>
              <DatePicker.ViewControl>
                <DatePicker.PrevTrigger>Prev</DatePicker.PrevTrigger>
                <DatePicker.ViewTrigger>
                  <DatePicker.RangeText />
                </DatePicker.ViewTrigger>
                <DatePicker.NextTrigger>Next</DatePicker.NextTrigger>
              </DatePicker.ViewControl>
              <DatePicker.Table>
                <DatePicker.TableBody>
                  {datePicker.getYearsGrid({ columns: 4 }).map((years, id) => (
                    <DatePicker.TableRow key={id}>
                      {years.map((year, id) => (
                        <DatePicker.TableCell key={id} value={year.value}>
                          <DatePicker.TableCellTrigger>{year.label}</DatePicker.TableCellTrigger>
                        </DatePicker.TableCell>
                      ))}
                    </DatePicker.TableRow>
                  ))}
                </DatePicker.TableBody>
              </DatePicker.Table>
            </>
          )}
        </DatePicker.Context>
      </DatePicker.View>
    </DatePicker.Root>
  )
}

API Reference

Root

PropDefaultType
asChild
boolean

Render as a different element type.

closeOnSelecttrue
boolean

Whether the calendar should close after the date selection is complete. This is ignored when the selection mode is `multiple`.

defaultOpen
boolean

The initial open state of the date picker when it is first rendered. Use when you do not need to control its open state.

defaultValue
string[]

The initial value of the date picker when it is first rendered. Use when you do not need to control the state of the date picker.

disabled
boolean

Whether the calendar is disabled.

fixedWeeks
boolean

Whether the calendar should have a fixed number of weeks. This renders the calendar with 6 weeks instead of 5 or 6.

focusedValue
string

The focused date.

format
(date: DateValue) => string

The format of the date to display in the input.

id
string

The unique identifier of the machine.

ids
Partial<{ root: string; table(id: string): string; tableHeader(id: string): string; tableBody(id: string): string; tableRow(id: string): string; content: string; cellTrigger(id: string): string; ... 9 more ...; positioner: string; }>

The ids of the elements in the date picker. Useful for composition.

isDateUnavailable
(date: DateValue, locale: string) => boolean

Returns whether a date of the calendar is available.

lazyMountfalse
boolean

Whether to enable lazy mounting

locale'en-US'
string

The locale (BCP 47 language tag) to use when formatting the date.

max
string

The maximum date for the date picker in the format yyyy-mm-dd

min
string

The minimum date for the date picker in the format yyyy-mm-dd

modal
boolean

Whether the calendar should be modal. This means that the calendar will block interaction with the rest of the page, and trap focus within it.

name
string

The `name` attribute of the input element.

numOfMonths
number

The number of months to display.

onExitComplete
() => void

Function called when the animation ends in the closed state.

onFocusChange
(details: FocusChangeDetails) => void

Function called when the focused date changes.

onOpenChange
(details: OpenChangeDetails) => void

Function called when the calendar opens or closes.

onValueChange
(details: ValueChangeDetails) => void

Function called when the value changes.

onViewChange
(details: ViewChangeDetails) => void

Function called when the view changes.

open
boolean

Whether the datepicker is open

positioning
PositioningOptions

The user provided options used to position the date picker content

present
boolean

Whether the node is present (controlled by the user)

readOnly
boolean

Whether the calendar is read-only.

selectionMode'single'
SelectionMode

The selection mode of the calendar. - `single` - only one date can be selected - `multiple` - multiple dates can be selected - `range` - a range of dates can be selected

startOfWeek
number

The first day of the week. `0` - Sunday `1` - Monday `2` - Tuesday `3` - Wednesday `4` - Thursday `5` - Friday `6` - Saturday

timeZone'UTC'
string

The time zone to use

translations
IntlTranslations

The localized messages to use.

unmountOnExitfalse
boolean

Whether to unmount on exit.

value
string[]

The value of the date picker

view'day'
DateView

The view of the calendar

Data AttributeValue
[data-scope]date-picker
[data-part]root
[data-state]"open" | "closed"
[data-disabled]Present when disabled
[data-readonly]Present when read-only

ClearTrigger

PropDefaultType
asChild
boolean

Render as a different element type.

Content

PropDefaultType
asChild
boolean

Render as a different element type.

Data AttributeValue
[data-scope]date-picker
[data-part]content
[data-state]"open" | "closed"
[data-placement]The placement of the content

Control

PropDefaultType
asChild
boolean

Render as a different element type.

Data AttributeValue
[data-scope]date-picker
[data-part]control
[data-disabled]Present when disabled

Input

PropDefaultType
asChild
boolean

Render as a different element type.

index
number

Data AttributeValue
[data-scope]date-picker
[data-part]input
[data-state]"open" | "closed"

Label

PropDefaultType
asChild
boolean

Render as a different element type.

Data AttributeValue
[data-scope]date-picker
[data-part]label
[data-state]"open" | "closed"
[data-disabled]Present when disabled
[data-readonly]Present when read-only

MonthSelect

PropDefaultType
asChild
boolean

Render as a different element type.

NextTrigger

PropDefaultType
asChild
boolean

Render as a different element type.

Positioner

PropDefaultType
asChild
boolean

Render as a different element type.

PresetTrigger

PropDefaultType
value
DateValue[] | DateRangePreset

asChild
boolean

Render as a different element type.

PrevTrigger

PropDefaultType
asChild
boolean

Render as a different element type.

RangeText

PropDefaultType
asChild
boolean

Render as a different element type.

TableBody

PropDefaultType
asChild
boolean

Render as a different element type.

Data AttributeValue
[data-scope]date-picker
[data-part]table-body
[data-view]The view of the tablebody
[data-disabled]Present when disabled

TableCell

PropDefaultType
value
number | DateValue

asChild
boolean

Render as a different element type.

columns
number

disabled
boolean

visibleRange
VisibleRange

TableCellTrigger

PropDefaultType
asChild
boolean

Render as a different element type.

TableHead

PropDefaultType
asChild
boolean

Render as a different element type.

Data AttributeValue
[data-scope]date-picker
[data-part]table-head
[data-view]The view of the tablehead
[data-disabled]Present when disabled

TableHeader

PropDefaultType
asChild
boolean

Render as a different element type.

Data AttributeValue
[data-scope]date-picker
[data-part]table-header
[data-view]The view of the tableheader
[data-disabled]Present when disabled

Table

PropDefaultType
asChild
boolean

Render as a different element type.

columns
number

Data AttributeValue
[data-scope]date-picker
[data-part]table
[data-columns]
[data-view]The view of the table

TableRow

PropDefaultType
asChild
boolean

Render as a different element type.

Data AttributeValue
[data-scope]date-picker
[data-part]table-row
[data-disabled]Present when disabled
[data-view]The view of the tablerow

Trigger

PropDefaultType
asChild
boolean

Render as a different element type.

Data AttributeValue
[data-scope]date-picker
[data-part]trigger
[data-placement]The placement of the trigger
[data-state]"open" | "closed"

ViewControl

PropDefaultType
asChild
boolean

Render as a different element type.

Data AttributeValue
[data-scope]date-picker
[data-part]view-control
[data-view]The view of the viewcontrol

View

PropDefaultType
view
DateView

asChild
boolean

Render as a different element type.

ViewTrigger

PropDefaultType
asChild
boolean

Render as a different element type.

Data AttributeValue
[data-scope]date-picker
[data-part]view-trigger
[data-view]The view of the viewtrigger

YearSelect

PropDefaultType
asChild
boolean

Render as a different element type.

Accessibility

Keyboard Support

KeyDescription
ArrowLeft
Moves focus to the previous day within the current week.
ArrowRight
Moves focus to the next day within the current week.
ArrowUp
Moves focus to the same day of the week in the previous week.
ArrowDown
Moves focus to the same day of the week in the next week.
Home
Moves focus to the first day of the current month.
End
Moves focus to the last day of the current month.
PageUp
Moves focus to the same day of the month in the previous month.
PageDown
Moves focus to the same day of the month in the next month.
Enter
Selects the focused date and closes the date picker.
Esc
Closes the date picker without selecting any date.