useNumberField для числовых полей

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


Импорт и базовое использование

import { useNumberField } from '@react-aria/numberfield';
import { useNumberFieldState } from '@react-stately/numberfield';
import { useLocale } from '@react-aria/i18n';
import React, { useRef } from 'react';

function NumberInput() {
  const { locale } = useLocale();
  const state = useNumberFieldState({ locale, minValue: 0, maxValue: 100, step: 1 });
  const ref = useRef();
  const { labelProps, inputProps, incrementButtonProps, decrementButtonProps } = useNumberField({ 
    minValue: 0,
    maxValue: 100,
    step: 1,
    value: state.value,
    onChange: state.setValue,
    formatOptions: { style: 'decimal', maximumFractionDigits: 2 }
  }, state, ref);

  return (
    <div>
      <label {...labelProps}>Количество</label>
      <div>
        <button {...decrementButtonProps}>-</button>
        <input {...inputProps} ref={ref} />
        <button {...incrementButtonProps}>+</button>
      </div>
    </div>
  );
}

Ключевые моменты:

  • useNumberFieldState отвечает за внутреннее состояние значения, управление шагами, ограничениями и форматированием.
  • useNumberField возвращает свойства для label, input и кнопок управления, полностью совместимые с ARIA.
  • ref необходим для корректной работы фокуса и управления клавиатурой.

Настройка шагов и диапазона

useNumberField позволяет задать минимальное и максимальное значение, а также шаг инкремента/декремента. Это делает числовой ввод полностью контролируемым.

const state = useNumberFieldState({
  minValue: 0,
  maxValue: 50,
  step: 5,
});

При нажатии кнопок + и - значение увеличивается или уменьшается на шаг, при этом автоматически соблюдается ограничение по минимальному и максимальному значению.


Форматирование и локализация

Библиотека поддерживает форматирование чисел согласно локали пользователя через Intl.NumberFormat.

const { inputProps } = useNumberField({
  value: state.value,
  onChange: state.setValue,
  formatOptions: { style: 'currency', currency: 'USD' }
}, state, ref);

Особенности:

  • style может быть 'decimal', 'currency', 'percent'.
  • currency используется при валютном формате.
  • Автоматически учитываются разделители тысяч и десятичные точки в зависимости от локали.

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

useNumberField поддерживает стандартные комбинации клавиш:

  • Arrow Up — увеличить значение на шаг
  • Arrow Down — уменьшить значение на шаг
  • Home — установить минимальное значение
  • End — установить максимальное значение

Это полностью соответствует рекомендациям WAI-ARIA и обеспечивает доступность для пользователей, использующих клавиатуру.


Интеграция с кнопками инкремента и декремента

Возвращаемые incrementButtonProps и decrementButtonProps позволяют легко создавать кнопки для изменения значения:

<button {...incrementButtonProps}>+</button>
<button {...decrementButtonProps}>-</button>

Особенности:

  • Кнопки автоматически становятся недоступными (disabled), когда значение достигает границы диапазона.
  • Поддерживается долгий клик и удержание для плавного увеличения/уменьшения значения.

Обработка пустых и некорректных значений

useNumberFieldState умеет корректно обрабатывать пустое поле, некорректный ввод и частично введённые числа. Например, ввод "12." или "-0" не приведёт к ошибкам и сохранит совместимость с форматированием и локалью.

const state = useNumberFieldState({
  minValue: 0,
  maxValue: 100,
  step: 1,
  value: '', // допускается пустое значение
});

Поддержка адаптивного форматирования

Можно динамически менять форматирование без потери состояния:

const [currency, setCurrency] = React.useState('USD');

const { inputProps } = useNumberField({
  value: state.value,
  onChange: state.setValue,
  formatOptions: { style: 'currency', currency }
}, state, ref);

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


Доступность и ARIA

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

  • role="spinbutton" на <input>
  • aria-valuemin, aria-valuemax, aria-valuenow для текущего значения
  • Связь с <label> через aria-labelledby
  • Обработка клавиатурного взаимодействия для всех пользователей

Библиотека снимает необходимость ручной реализации ARIA для числовых полей, что уменьшает вероятность ошибок и повышает доступность приложения.


Заключение по функционалу (без формального завершения)

Использование useNumberField в связке с useNumberFieldState позволяет создавать мощные, доступные и локализованные числовые поля в React-приложениях. Управление шагами, диапазонами, клавиатурой, форматированием и кнопками инкремента/декремента реализуется легко и соответствует стандартам ARIA. Такой подход гарантирует корректное поведение на всех устройствах и в разных локалях, избавляя от необходимости писать сложную логику с нуля.