useTimeField для ввода времени

useTimeField — один из ключевых хуков библиотеки React Aria, предназначенный для создания полностью доступных и гибко настраиваемых полей ввода времени. Он реализует сложную логику работы с часовыми и минутными сегментами, поддерживает клавиатурную навигацию, управление фокусом, локализацию форматов времени и взаимодействие с ассистивными технологиями.

В отличие от стандартного HTML-элемента <input type="time">, хук предоставляет полный контроль над отображением и поведением интерфейса, позволяя разработчику создавать кастомные компоненты с сохранением доступности.


Основные возможности

useTimeField реализует целый набор функций, необходимых для корректного ввода времени:

Сегментированный ввод времени

Время разбивается на независимые сегменты:

  • часы
  • минуты
  • секунды (опционально)
  • период AM/PM
  • разделители

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

Поддержка клавиатуры

Реализованы стандартные действия:

  • стрелки вверх/вниз изменяют значение сегмента
  • стрелки влево/вправо перемещают фокус между сегментами
  • ввод цифр напрямую изменяет значение
  • Tab перемещает фокус между элементами формы

Локализация

Компонент автоматически адаптируется под региональные настройки:

  • формат времени (12-часовой или 24-часовой)
  • порядок сегментов
  • локализованные разделители

Поддержка доступности

Интеграция с ARIA-атрибутами обеспечивает корректную работу со скринридерами.


Архитектура работы

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

  • useTimeField — логика поля времени
  • useTimeFieldState из React Stately — управление состоянием
  • useDateSegment — обработка отдельных сегментов времени

Типичная структура компонента выглядит следующим образом:

TimeField
 ├─ TimeSegment (hour)
 ├─ TimeSegment (minute)
 ├─ TimeSegment (second)
 └─ TimeSegment (dayPeriod)

Каждый сегмент управляется отдельно, но синхронизирован с общим состоянием времени.


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

Для работы требуются следующие пакеты:

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

Базовое использование

Простейшая реализация поля времени:

import {useRef} from "react";
import {useTimeField} from "@react-aria/datepicker";
import {useTimeFieldState} from "@react-stately/datepicker";
import {useLocale} from "@react-aria/i18n";
import {Time} from "@internationalized/date";

function TimeField(props) {
  let {locale} = useLocale();
  let state = useTimeFieldState({
    ...props,
    locale
  });

  let ref = useRef();
  let {fieldProps} = useTimeField(props, state, ref);

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

Компонент рендерит набор сегментов времени, которые отображаются и управляются независимо.


Компонент сегмента времени

Каждый сегмент обрабатывается хуком useDateSegment.

import {useRef} from "react";
import {useDateSegment} from "@react-aria/datepicker";

function DateSegment({segment, state}) {
  let ref = useRef();
  let {segmentProps} = useDateSegment(segment, state, ref);

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

Типы сегментов могут быть следующими:

Тип сегмента Описание
hour часы
minute минуты
second секунды
dayPeriod AM/PM
literal разделители

Сегменты literal не редактируются и служат только для отображения.


Управление состоянием времени

Состояние поля управляется через useTimeFieldState.

let state = useTimeFieldState({
  locale,
  defaultValue: new Time(14, 30)
});

Объект Time описывает время:

new Time(hour, minute, second)

Пример:

new Time(9, 45)

Контролируемое и неконтролируемое состояние

Неконтролируемый режим

<TimeField defaultValue={new Time(10, 0)} />

Компонент сам управляет состоянием.

Контролируемый режим

const [time, setTime] = useState(new Time(12, 30));

<TimeField
  value={time}
  onCha nge={setTime}
/>

В этом случае состояние полностью контролируется React.


Ограничения диапазона времени

Можно задать минимальное и максимальное значение времени.

<TimeField
  minValue={new Time(9, 0)}
  maxValue={new Time(18, 0)}
/>

Если пользователь пытается ввести значение вне диапазона, оно автоматически корректируется.


Формат времени

Формат определяется локалью.

Например:

Локаль Формат
en-US 12-часовой
de-DE 24-часовой
fr-FR 24-часовой

Пример:

9:30 AM

или

21:30

Отображение секунд

Секунды добавляются через опцию granularity.

<TimeField granularity="second" />

Поддерживаемые значения:

  • "hour"
  • "minute"
  • "second"

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

14 : 35 : 42

Шаг изменения времени

Можно задать шаг изменения значений.

<TimeField minuteStep={5} />

Теперь минуты будут изменяться с шагом 5:

00
05
10
15

Плейсхолдер времени

Пока значение не введено, отображается placeholder.

--:--

Каждый сегмент имеет собственный placeholder:

Сегмент Placeholder
hour ––
minute ––

Стилизация сегментов

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

Пример:

<span
  {...segmentProps}
  ref={ref}
  className={segment.isPlaceholder ? "placeholder" : "value"}
>
  {segment.text}
</span>

Дополнительные состояния сегмента:

Свойство Описание
isEditable сегмент редактируемый
isPlaceholder отображается placeholder
isFocused сегмент в фокусе

Управление фокусом

Фокус автоматически перемещается между сегментами.

Примеры:

Действие Результат
ArrowRight следующий сегмент
ArrowLeft предыдущий сегмент
Tab следующий элемент формы

Доступность

useTimeField автоматически добавляет необходимые ARIA-атрибуты:

  • role="group"
  • aria-labelledby
  • aria-describedby

Каждый сегмент имеет роль:

spinbutton

Это позволяет скринридерам корректно объявлять изменения значений.


Валидация

Можно добавить пользовательскую проверку.

<TimeField
  validate={(time) => {
    if (time.hour < 9) {
      return "Рабочий день начинается с 9:00";
    }
  }}
/>

Если функция возвращает строку — поле считается невалидным.


Интеграция с формами

Компонент легко интегрируется с HTML-формами.

Пример:

<form>
  <TimeField name="meetingTime" />
</form>

При отправке формы значение сериализуется.


Пользовательские компоненты интерфейса

useTimeField позволяет реализовывать собственный дизайн.

Пример интерфейса:

[ 10 ] : [ 30 ]  AM

Стили могут включать:

  • рамки сегментов
  • подсветку активного сегмента
  • анимацию изменения значений

Полный пример компонента

import {useRef} from "react";
import {useTimeField} from "@react-aria/datepicker";
import {useTimeFieldState} from "@react-stately/datepicker";
import {useDateSegment} from "@react-aria/datepicker";
import {useLocale} from "@react-aria/i18n";

function TimeField(props) {
  let {locale} = useLocale();
  let state = useTimeFieldState({...props, locale});
  let ref = useRef();
  let {fieldProps} = useTimeField(props, state, ref);

  return (
    <div {...fieldProps} ref={ref}>
      {state.segments.map((segment, i) => (
        <Segment key={i} segment={segment} state={state} />
      ))}
    </div>
  );
}

function Segment({segment, state}) {
  let ref = useRef();
  let {segmentProps} = useDateSegment(segment, state, ref);

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

Когда используется useTimeField

Хук применяется в интерфейсах, где требуется точный ввод времени:

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

В сочетании с useDateField и useDatePicker можно реализовать сложные интерфейсы выбора даты и времени, полностью контролируемые на уровне React и при этом соответствующие стандартам доступности.