Диапазонные слайдеры

Диапазонные слайдеры (range sliders) предоставляют пользователю возможность выбирать одно или несколько значений на непрерывной или дискретной шкале. В React Aria такие компоненты обеспечивают полную доступность (accessibility), включая поддержку клавиатуры, экранных читалок и правильную семантику ARIA.

React Aria разделяет логику состояния и рендеринг, что позволяет использовать библиотеку совместно с любыми UI-библиотеками или кастомными компонентами.


Структура диапазонного слайдера

Основные элементы диапазонного слайдера:

  1. Slider – контейнер, управляющий состоянием и взаимодействиями.
  2. Thumb – ползунок, который перемещается по шкале.
  3. Track – визуальная линия, на которой перемещается ползунок.
  4. Range – участок, выделенный между минимальным и максимальным значениями для диапазонных слайдеров.

Создание состояния слайдера

React Aria предоставляет хук useSlider и useSliderState для управления значениями и событиями.

Пример создания состояния диапазонного слайдера с двумя ползунками:

import { useSliderState } from "@react-stately/slider";

const sliderState = useSliderState({
  minValue: 0,
  maxValue: 100,
  step: 1,
  numberFormatter: new Intl.NumberFormat('ru-RU'),
  defaultValue: [20, 80]
});

Ключевые параметры:

  • minValue и maxValue – границы шкалы.
  • step – шаг изменения значения при перемещении ползунка.
  • defaultValue – начальные значения ползунков (для диапазонного слайдера массив из двух чисел).
  • numberFormatter – форматирование числового отображения значений.

useSliderState автоматически следит за положением ползунков, предотвращает пересечение и вычисляет процентное значение для рендеринга.


Реализация слайдера с помощью useSlider

Хук useSlider подключает DOM-элементы к состоянию и обеспечивает доступность:

import { useSlider } from "@react-aria/slider";

function RangeSlider({ sliderState }) {
  const { groupProps, trackProps, labelProps } = useSlider({
    minValue: 0,
    maxValue: 100,
    step: 1
  }, sliderState);

  return (
    <div {...groupProps} className="slider-container">
      <label {...labelProps}>Выберите диапазон</label>
      <div {...trackProps} className="slider-track">
        {sliderState.values.map((value, index) => (
          <Thumb key={index} index={index} sliderState={sliderState} />
        ))}
      </div>
    </div>
  );
}

Пояснения:

  • groupProps – атрибуты контейнера для ARIA.
  • trackProps – атрибуты дорожки слайдера.
  • labelProps – семантическая метка для экранных читалок.
  • sliderState.values – текущие значения всех ползунков, обновляемые при взаимодействии пользователя.

Компонент Thumb

Ползунок требует собственного хука useSliderThumb для обработки перетаскивания и клавиатуры:

import { useSliderThumb } from "@react-aria/slider";

function Thumb({ index, sliderState }) {
  const ref = React.useRef();
  const { thumbProps, inputProps } = useSliderThumb({ index }, sliderState, ref);

  return (
    <div {...thumbProps} ref={ref} className="slider-thumb">
      <input {...inputProps} />
    </div>
  );
}

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

  • thumbProps – обрабатывают события мыши и касания.
  • inputProps – обеспечивают взаимодействие с клавиатурой и чтение значения экранными читалками.
  • Поддерживается несколько ползунков на одной дорожке, каждый с индексом.

Поддержка диапазона

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

function RangeTrack({ sliderState }) {
  const min = sliderState.values[0];
  const max = sliderState.values[1];

  const left = ((min - sliderState.minValue) / (sliderState.maxValue - sliderState.minValue)) * 100;
  const width = ((max - min) / (sliderState.maxValue - sliderState.minValue)) * 100;

  return <div className="slider-range" style={{ left: `${left}%`, width: `${width}%` }} />;
}

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

  • left – позиция начала выделенного диапазона.
  • width – длина диапазона, соответствующая разнице между ползунками.
  • Использование процентных значений обеспечивает корректное масштабирование при любых размерах контейнера.

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

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

  • role="slider"
  • aria-valuemin, aria-valuemax, aria-valuenow
  • aria-valuetext для форматированных значений
  • Поддержка стрелок, PageUp/PageDown, Home/End для точного изменения значений.

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


Кастомизация внешнего вида

React Aria отвечает только за логику и доступность. Визуальный рендеринг можно настроить через CSS или любую UI-библиотеку. Основные элементы для стилизации:

  • .slider-container – обёртка всего слайдера.
  • .slider-track – линия слайдера.
  • .slider-range – выделенный диапазон.
  • .slider-thumb – ползунок.

Пример минимального CSS:

.slider-track {
  position: relative;
  height: 4px;
  background: #ccc;
  border-radius: 2px;
}

.slider-range {
  position: absolute;
  height: 100%;
  background: #007aff;
  border-radius: 2px;
}

.slider-thumb {
  position: absolute;
  width: 16px;
  height: 16px;
  background: #fff;
  border: 2px solid #007aff;
  border-radius: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  cursor: pointer;
}

Работа с шагами и форматированием

React Aria позволяет задавать шаг изменения, что важно для точного выбора:

const sliderState = useSliderState({
  minValue: 0,
  maxValue: 50,
  step: 5,
  defaultValue: [10, 30]
});

Форматирование отображаемого значения через numberFormatter поддерживает локализацию и добавление единиц измерения:

numberFormatter: new Intl.NumberFormat('ru-RU', { style: 'unit', unit: 'kg' })

Особенности взаимодействия с пользователем

  • Перетаскивание мышью или касанием изменяет значения плавно.
  • Клавиатура позволяет точно управлять каждым ползунком.
  • Доступность обеспечивается без дополнительного кода для ARIA.
  • Поддержка нескольких ползунков на одной шкале реализуется через индекс ползунка.

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