useDatePicker для выбора даты

Хук useDatePicker из библиотеки React Aria реализует полноценный, доступный (accessible) интерфейс выбора даты. Он объединяет текстовый ввод даты, кнопку открытия календаря и всплывающий календарный интерфейс в единую систему с корректной ARIA-разметкой и поведением клавиатуры.

Хук не рендерит готовый UI. Он предоставляет набор пропсов и состояний, которые необходимо применить к собственным React-компонентам.

useDatePicker решает несколько задач:

  • управление состоянием даты
  • синхронизация текстового ввода и календаря
  • поддержка локализации
  • корректная ARIA-разметка
  • навигация клавиатурой
  • работа со всплывающим календарём
  • поддержка различных календарных систем

В основе работы лежит взаимодействие трёх библиотек:

  • React Aria — поведение и доступность
  • React Stately — управление состоянием
  • @internationalized/date — модель даты и календарные операции

Базовая архитектура DatePicker

Компонент выбора даты состоит из нескольких частей:

1. Контейнер DatePicker

Отвечает за общую структуру компонента.

2. Поле ввода даты

Разбито на сегменты:

  • день
  • месяц
  • год

Каждый сегмент редактируется отдельно.

3. Кнопка открытия календаря

Открывает всплывающий календарь.

4. Popover

Контейнер всплывающего окна.

5. Calendar

Календарный интерфейс выбора даты.


Установка зависимостей

Для работы useDatePicker требуется несколько пакетов:

npm install react-aria react-stately @internationalized/date

Создание состояния DatePicker

Состояние компонента управляется хуком useDatePickerState.

import {useDatePickerState} from 'react-stately'
import {useDatePicker} from 'react-aria'

Пример создания состояния:

let state = useDatePickerState({
  value: null,
  onChange: setDate
})

state управляет:

  • выбранной датой
  • открытием календаря
  • фокусом
  • редактированием сегментов

Базовый пример использования

Минимальная реализация DatePicker:

function DatePicker(props) {
  let state = useDatePickerState(props)

  let ref = React.useRef()

  let {
    groupProps,
    fieldProps,
    buttonProps,
    dialogProps,
    calendarProps
  } = useDatePicker(props, state, ref)

  return (
    <div {...groupProps} ref={ref}>
      <DateField {...fieldProps} />

      <button {...buttonProps}>
        ?
      </button>

      {state.isOpen && (
        <Popover>
          <div {...dialogProps}>
            <Calendar {...calendarProps} />
          </div>
        </Popover>
      )}
    </div>
  )
}

useDatePicker возвращает набор пропсов:

prop назначение
groupProps контейнер DatePicker
fieldProps поле ввода даты
buttonProps кнопка открытия календаря
dialogProps контейнер popover
calendarProps календарь

Структура поля даты

DatePicker использует компонент DateField, который разбивает дату на сегменты.

Каждый сегмент редактируется отдельно.

Пример сегментов:

[ 12 ] [ 05 ] [ 2026 ]
  день   месяц  год

Каждый сегмент:

  • получает фокус
  • изменяется стрелками
  • редактируется цифрами

Реализация DateField

import {useDateField} from 'react-aria'
import {useDateFieldState} from 'react-stately'

function DateField(props) {
  let state = useDateFieldState(props)
  let ref = React.useRef()

  let {fieldProps} = useDateField(props, state, ref)

  return (
    <div {...fieldProps} ref={ref}>
      {state.segments.map(segment => (
        <DateSegment
          key={segment.type}
          segment={segment}
          state={state}
        />
      ))}
    </div>
  )
}

Сегменты даты

Каждый сегмент управляется useDateSegment.

import {useDateSegment} from 'react-aria'

function DateSegment({segment, state}) {
  let ref = React.useRef()

  let {segmentProps} = useDateSegment(segment, state, ref)

  return (
    <span {...segmentProps} ref={ref}>
      {segment.text}
    </span>
  )
}

Сегменты бывают следующих типов:

тип описание
day день
month месяц
year год
hour часы
minute минуты
literal разделители

Работа с календарём

Для отображения календаря используется useCalendarState и useCalendar.

import {useCalendar} from 'react-aria'
import {useCalendarState} from 'react-stately'

Пример:

function Calendar(props) {
  let state = useCalendarState(props)
  let ref = React.useRef()

  let {calendarProps, prevButtonProps, nextButtonProps} =
    useCalendar(props, state)

  return (
    <div {...calendarProps} ref={ref}>
      <button {...prevButtonProps}>Prev</button>
      <button {...nextButtonProps}>Next</button>

      <CalendarGrid state={state} />
    </div>
  )
}

Генерация сетки календаря

Календарь состоит из недель.

import {useCalendarGrid} from 'react-aria'

function CalendarGrid({state}) {
  let {gridProps, headerProps, weekDays} =
    useCalendarGrid({}, state)

  return (
    <table {...gridProps}>
      <thead {...headerProps}>
        <tr>
          {weekDays.map(day => (
            <th key={day}>{day}</th>
          ))}
        </tr>
      </thead>

      <tbody>
        {[...state.getWeeksInMonth()].map((week, i) => (
          <tr key={i}>
            {week.map(date => (
              <CalendarCell key={date} date={date} state={state}/>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  )
}

Ячейки календаря

Каждый день реализуется через useCalendarCell.

import {useCalendarCell} from 'react-aria'

function CalendarCell({state, date}) {
  let ref = React.useRef()

  let {
    cellProps,
    buttonProps,
    isSelected,
    isOutsideVisibleRange
  } = useCalendarCell({date}, state, ref)

  return (
    <td {...cellProps}>
      <button {...buttonProps} ref={ref}>
        {date.day}
      </button>
    </td>
  )
}

Локализация

React Aria автоматически поддерживает локализацию.

Пример:

import {I18nProvider} from 'react-aria'

<I18nProvider locale="ru-RU">
  <DatePicker />
</I18nProvider>

Это влияет на:

  • формат даты
  • порядок сегментов
  • названия месяцев
  • первый день недели

Работа с объектами даты

React Aria использует типы из @internationalized/date.

Пример:

import {CalendarDate} from '@internationalized/date'

let date = new CalendarDate(2026, 3, 15)

Преимущества:

  • независимость от Date
  • поддержка разных календарей
  • корректная работа с часовыми поясами

Ограничение диапазона дат

Можно задать допустимый диапазон дат.

<DatePicker
  minValue={new CalendarDate(2020,1,1)}
  maxValue={new CalendarDate(2030,12,31)}
/>

В этом случае:

  • недопустимые даты блокируются
  • календарь автоматически ограничивает выбор

Значение по умолчанию

<DatePicker
  defaultValue={new CalendarDate(2025, 6, 10)}
/>

Отличие:

свойство поведение
value контролируемый компонент
defaultValue неконтролируемый

Обработка изменений

<DatePicker
  onCha nge={(date) => {
    console.log(date.toString())
  }}
/>

Возвращается объект:

CalendarDate

Пример:

2026-03-15

Управление открытием календаря

Можно контролировать popover вручную.

<DatePicker
  isOpen={isOpen}
  onOpenCha nge={setIsOpen}
/>

Это позволяет:

  • интегрировать DatePicker в сложные формы
  • управлять всплывающим интерфейсом

Доступность (Accessibility)

useDatePicker автоматически реализует:

ARIA роли

  • group
  • spinbutton
  • dialog
  • grid

Управление клавиатурой

клавиша действие
ArrowUp увеличить сегмент
ArrowDown уменьшить
ArrowLeft предыдущий сегмент
ArrowRight следующий сегмент
Enter открыть календарь
Esc закрыть popover

Работа с фокусом

React Aria автоматически:

  • переносит фокус между сегментами
  • сохраняет фокус после закрытия popover
  • поддерживает screen readers

Поддержка разных календарей

@internationalized/date поддерживает:

  • Gregorian
  • Islamic
  • Hebrew
  • Japanese
  • Indian

Пример:

<DatePicker
  calendar="islamic"
/>

DatePicker с временем

Для выбора даты и времени используется:

useDatePicker + useTimeField

Либо готовый хук:

useDateRangePicker

Стилизация

React Aria не включает CSS.

Стили применяются через:

  • CSS
  • Tailwind
  • styled-components

Пример:

.datepicker {
  display: flex;
  gap: 8px;
}

.calendar {
  background: white;
  border: 1px solid #ccc;
}

Типичная структура компонента

Полноценный DatePicker состоит из:

DatePicker
 ├─ DateField
 │   ├─ DateSegment
 │   ├─ DateSegment
 │   └─ DateSegment
 │
 ├─ Button
 │
 └─ Popover
     └─ Calendar
         ├─ CalendarGrid
         │   └─ CalendarCell

Каждый элемент получает поведение через React Aria.


Производительность

React Aria оптимизирован для:

  • минимального количества ререндеров
  • работы с большими формами
  • корректной синхронизации состояния

DatePicker ререндерится только при изменении:

  • даты
  • фокуса
  • состояния popover

Практические сценарии использования

Наиболее распространённые применения:

формы бронирования

Дата заезда
Дата выезда

выбор даты события

Дата встречи
Дата дедлайна

фильтрация данных

От
До

Свойства useDatePicker

Основные параметры:

свойство описание
value выбранная дата
defaultValue дата по умолчанию
onChange обработчик изменения
minValue минимальная дата
maxValue максимальная дата
isDisabled блокировка
isReadOnly только чтение
isOpen состояние popover
onOpenChange управление popover
locale локализация

Когда использовать useDatePicker

Хук применяется в случаях:

  • сложные формы
  • высокая доступность интерфейса
  • кастомный UI календаря
  • международные приложения
  • поддержка различных календарных систем

Он позволяет полностью контролировать структуру и внешний вид компонента, сохраняя стандарты доступности и поведения интерфейса.