Components
Date picker

Date Picker

The Date Picker is a comprehensive tool for date selection within your application. It supports various view modes (day, month, year), single date selection, and range selection. This component also allows the rendering of multiple grids for a broader date range view.

Usage

To get started, import the necessary components from the package:

import {
  DatePicker,
  DatePickerControl,
  DatePickerInput,
  DatePickerTrigger,
  DatePickerClearTrigger,
  DatePickerContent,
  DatePickerYearSelect,
  DatePickerMonthSelect,
  DatePickerPrevTrigger,
  DatePickerViewTrigger,
  DatePickerNextTrigger,
  DatePickerGrid,
  DatePickerRowHeader,
  DatePickerColumnHeader,
  DatePickerRowGroup,
  DatePickerRow,
  DatePickerDayCell,
  DatePickerDayCellTrigger,
  DatePickerMonthCell,
  DatePickerMonthCellTrigger,
  DatePickerYearCell,
  DatePickerYearCellTrigger,
} from '@ark-ui/react'

Here is an example of how to use the Date Picker component:

import { Portal } from '@zag-js/react'
import {
  DatePicker,
  DatePickerClearTrigger,
  DatePickerColumnHeader,
  DatePickerContent,
  DatePickerControl,
  DatePickerDayCell,
  DatePickerDayCellTrigger,
  DatePickerGrid,
  DatePickerInput,
  DatePickerMonthCell,
  DatePickerMonthCellTrigger,
  DatePickerMonthSelect,
  DatePickerNextTrigger,
  DatePickerPositioner,
  DatePickerPrevTrigger,
  DatePickerRow,
  DatePickerRowGroup,
  DatePickerRowHeader,
  DatePickerTrigger,
  DatePickerViewTrigger,
  DatePickerYearCell,
  DatePickerYearCellTrigger,
  DatePickerYearSelect,
} from '@ark-ui/react'

const Basic = () => (
  <DatePicker>
    {(api) => (
      <>
        <DatePickerControl>
          <span>View mode: {api.view}</span>
          <DatePickerInput />
          <DatePickerTrigger>🗓</DatePickerTrigger>
          <DatePickerClearTrigger>Clear</DatePickerClearTrigger>
        </DatePickerControl>
        <Portal>
          <DatePickerPositioner>
            <DatePickerContent>
              <DatePickerYearSelect />
              <DatePickerMonthSelect />
              <div>
                <DatePickerPrevTrigger>Prev</DatePickerPrevTrigger>
                <DatePickerViewTrigger>
                  {api.view === 'day' && api.visibleRangeText.start}
                  {api.view === 'month' && api.visibleRange.start.year}
                  {api.view === 'year' && `${api.getDecade().start} - ${api.getDecade().end}`}
                </DatePickerViewTrigger>
                <DatePickerNextTrigger>Next</DatePickerNextTrigger>
              </div>
              {api.view === 'day' && (
                <DatePickerGrid>
                  <DatePickerRowHeader>
                    {api.weekDays.map((day, i) => (
                      <DatePickerColumnHeader key={i} aria-label={day.long}>
                        {day.narrow}
                      </DatePickerColumnHeader>
                    ))}
                  </DatePickerRowHeader>
                  <DatePickerRowGroup>
                    {api.weeks.map((week, id) => (
                      <DatePickerRow key={id}>
                        {week.map((day, id) => (
                          <DatePickerDayCell key={id} value={day}>
                            <DatePickerDayCellTrigger>{day.day}</DatePickerDayCellTrigger>
                          </DatePickerDayCell>
                        ))}
                      </DatePickerRow>
                    ))}
                  </DatePickerRowGroup>
                </DatePickerGrid>
              )}
              {api.view === 'month' && (
                <DatePickerGrid>
                  <DatePickerRowGroup>
                    {api.getMonthsGrid({ columns: 4, format: 'short' }).map((months, row) => (
                      <DatePickerRow key={row}>
                        {months.map((month, index) => (
                          <DatePickerMonthCell key={index} value={month.value}>
                            <DatePickerMonthCellTrigger>{month.label}</DatePickerMonthCellTrigger>
                          </DatePickerMonthCell>
                        ))}
                      </DatePickerRow>
                    ))}
                  </DatePickerRowGroup>
                </DatePickerGrid>
              )}
              {api.view === 'year' && (
                <DatePickerGrid>
                  <DatePickerRowGroup>
                    {api.getYearsGrid({ columns: 4 }).map((years, row) => (
                      <DatePickerRow key={row}>
                        {years.map((year, index) => (
                          <DatePickerYearCell key={index} value={year.value}>
                            <DatePickerYearCellTrigger>{year.label}</DatePickerYearCellTrigger>
                          </DatePickerYearCell>
                        ))}
                      </DatePickerRow>
                    ))}
                  </DatePickerRowGroup>
                </DatePickerGrid>
              )}
            </DatePickerContent>
          </DatePickerPositioner>
        </Portal>
      </>
    )}
  </DatePicker>
)

Range Selection with Single Grid

To create a Date Picker that allows a range selection, set the selectionMode prop to “range”. This renders a single grid view where the user can select a start and end date:

import { Portal } from '@zag-js/react'
import {
  DatePicker,
  DatePickerClearTrigger,
  DatePickerColumnHeader,
  DatePickerContent,
  DatePickerControl,
  DatePickerDayCell,
  DatePickerDayCellTrigger,
  DatePickerGrid,
  DatePickerInput,
  DatePickerMonthCell,
  DatePickerMonthCellTrigger,
  DatePickerMonthSelect,
  DatePickerNextTrigger,
  DatePickerPositioner,
  DatePickerPrevTrigger,
  DatePickerRow,
  DatePickerRowGroup,
  DatePickerRowHeader,
  DatePickerTrigger,
  DatePickerViewTrigger,
  DatePickerYearCell,
  DatePickerYearCellTrigger,
  DatePickerYearSelect,
} from '@ark-ui/react'

const RangeWithSingleGrid = () => (
  <DatePicker selectionMode="range">
    {(api) => (
      <>
        <DatePickerControl>
          <span>View mode: {api.view}</span>
          <DatePickerInput />
          <DatePickerTrigger>🗓</DatePickerTrigger>
          <DatePickerClearTrigger>Clear</DatePickerClearTrigger>
        </DatePickerControl>
        <Portal>
          <DatePickerPositioner>
            <DatePickerContent>
              <DatePickerYearSelect />
              <DatePickerMonthSelect />
              <div>
                <DatePickerPrevTrigger>Prev</DatePickerPrevTrigger>
                <DatePickerViewTrigger>
                  {api.view === 'day' && api.visibleRangeText.start}
                  {api.view === 'month' && api.visibleRange.start.year}
                  {api.view === 'year' && `${api.getDecade().start} - ${api.getDecade().end}`}
                </DatePickerViewTrigger>
                <DatePickerNextTrigger>Next</DatePickerNextTrigger>
              </div>
              {api.view === 'day' && (
                <DatePickerGrid>
                  <DatePickerRowHeader>
                    {api.weekDays.map((day, i) => (
                      <DatePickerColumnHeader key={i} aria-label={day.long}>
                        {day.narrow}
                      </DatePickerColumnHeader>
                    ))}
                  </DatePickerRowHeader>
                  <DatePickerRowGroup>
                    {api.weeks.map((week, id) => (
                      <DatePickerRow key={id}>
                        {week.map((day, id) => (
                          <DatePickerDayCell key={id} value={day}>
                            <DatePickerDayCellTrigger>{day.day}</DatePickerDayCellTrigger>
                          </DatePickerDayCell>
                        ))}
                      </DatePickerRow>
                    ))}
                  </DatePickerRowGroup>
                </DatePickerGrid>
              )}
              {api.view === 'month' && (
                <DatePickerGrid>
                  <DatePickerRowGroup>
                    {api.getMonthsGrid({ columns: 4, format: 'short' }).map((months, row) => (
                      <DatePickerRow key={row}>
                        {months.map((month, index) => (
                          <DatePickerMonthCell key={index} value={month.value}>
                            <DatePickerMonthCellTrigger>{month.label}</DatePickerMonthCellTrigger>
                          </DatePickerMonthCell>
                        ))}
                      </DatePickerRow>
                    ))}
                  </DatePickerRowGroup>
                </DatePickerGrid>
              )}
              {api.view === 'year' && (
                <DatePickerGrid>
                  <DatePickerRowGroup>
                    {api.getYearsGrid({ columns: 4 }).map((years, row) => (
                      <DatePickerRow key={row}>
                        {years.map((year, index) => (
                          <DatePickerYearCell key={index} value={year.value}>
                            <DatePickerYearCellTrigger>{year.label}</DatePickerYearCellTrigger>
                          </DatePickerYearCell>
                        ))}
                      </DatePickerRow>
                    ))}
                  </DatePickerRowGroup>
                </DatePickerGrid>
              )}
            </DatePickerContent>
          </DatePickerPositioner>
        </Portal>
      </>
    )}
  </DatePicker>
)

Range Selection with Two Grids

In some cases, you might want to display two consecutive months at the same time to facilitate a broader range selection. This can be achieved by setting the numOfMonths prop to 2:

import { Portal } from '@zag-js/react'
import {
  DatePicker,
  DatePickerClearTrigger,
  DatePickerColumnHeader,
  DatePickerContent,
  DatePickerControl,
  DatePickerDayCell,
  DatePickerDayCellTrigger,
  DatePickerGrid,
  DatePickerInput,
  DatePickerMonthCell,
  DatePickerMonthCellTrigger,
  DatePickerMonthSelect,
  DatePickerNextTrigger,
  DatePickerPositioner,
  DatePickerPrevTrigger,
  DatePickerRow,
  DatePickerRowGroup,
  DatePickerRowHeader,
  DatePickerTrigger,
  DatePickerViewTrigger,
  DatePickerYearCell,
  DatePickerYearCellTrigger,
  DatePickerYearSelect,
} from '@ark-ui/react'

const RangeWithTwoGrids = () => (
  <DatePicker selectionMode="range" numOfMonths={2}>
    {(api) => {
      const offset = api.getOffset(1)
      return (
        <>
          <DatePickerControl>
            <span>View mode: {api.view}</span>
            <DatePickerInput />
            <DatePickerTrigger>🗓</DatePickerTrigger>
            <DatePickerClearTrigger>Clear</DatePickerClearTrigger>
          </DatePickerControl>
          <Portal>
            <DatePickerPositioner>
              <DatePickerContent>
                <div style={{ display: 'flex', justifyContent: 'space-between' }}>
                  <DatePickerPrevTrigger>Prev</DatePickerPrevTrigger>
                  <time>{api.visibleRangeText.start}</time>
                  <time>{api.visibleRangeText.end}</time>
                  <DatePickerNextTrigger>Next</DatePickerNextTrigger>
                </div>
                <div style={{ display: 'flex', justifyContent: 'space-between', gap: '24px' }}>
                  <DatePickerGrid>
                    <DatePickerRowHeader>
                      {api.weekDays.map((day, i) => (
                        <DatePickerColumnHeader key={i} aria-label={day.long}>
                          {day.narrow}
                        </DatePickerColumnHeader>
                      ))}
                    </DatePickerRowHeader>
                    <DatePickerRowGroup>
                      {api.weeks.map((week, id) => (
                        <DatePickerRow key={id}>
                          {week.map((day, id) => (
                            <DatePickerDayCell key={id} value={day}>
                              <DatePickerDayCellTrigger>{day.day}</DatePickerDayCellTrigger>
                            </DatePickerDayCell>
                          ))}
                        </DatePickerRow>
                      ))}
                    </DatePickerRowGroup>
                  </DatePickerGrid>

                  <DatePickerGrid>
                    <DatePickerRowHeader>
                      {api.weekDays.map((day, i) => (
                        <DatePickerColumnHeader key={i} aria-label={day.long}>
                          {day.narrow}
                        </DatePickerColumnHeader>
                      ))}
                    </DatePickerRowHeader>
                    <DatePickerRowGroup>
                      {offset.weeks.map((week, id) => (
                        <DatePickerRow key={id}>
                          {week.map((day, id) => (
                            <DatePickerDayCell key={id} value={day} offset={offset}>
                              <DatePickerDayCellTrigger>{day.day}</DatePickerDayCellTrigger>
                            </DatePickerDayCell>
                          ))}
                        </DatePickerRow>
                      ))}
                    </DatePickerRowGroup>
                  </DatePickerGrid>
                </div>
              </DatePickerContent>
            </DatePickerPositioner>
          </Portal>
        </>
      )
    }}
  </DatePicker>
)

Conclusion

The Date Picker component provides a versatile solution for date selection needs in your applications. With support for different view modes, single and range date selection, and the ability to render multiple grids, it offers a wide range of customization and usability options.

Previous

Combobox

Next

Dialog