Навигация с клавиатуры

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


Основные принципы

Навигация с клавиатуры строится вокруг следующих ключевых концепций:

  1. Фокусируемость элементов Любой элемент, по которому пользователь должен перемещаться с клавиатуры, должен поддерживать фокус. В HTML это достигается с помощью атрибута tabindex. Например:

    <div tabindex="0">Элемент 1</div>
    <div tabindex="0">Элемент 2</div>

    В Atomico можно управлять этим через JSX и реактивные свойства:

    import { c, useRef } from "atomico";
    
    const Item = c(() => {
        const ref = useRef();
    
        return <div ref={ref} tabindex="0">Навигационный элемент</div>;
    });
  2. Обработка событий клавиатуры Для отслеживания нажатий клавиш используется событие keydown. В Atomico можно привязать его через JSX:

    const handleKeyDown = (event) => {
        if (event.key === "ArrowDown") {
            // Действие при стрелке вниз
        }
    };
    
    return <div onKeyD own={handleKeyDown} tabindex="0">Навигация</div>;

    Важно предотвращать стандартное поведение при необходимости, например:

    event.preventDefault();

Реактивная фокусировка

Atomico поддерживает реактивные ссылки на элементы через useRef. Это позволяет программно управлять фокусом:

import { c, useRef } from "atomico";

const List = c(() => {
    const items = [useRef(), useRef(), useRef()];

    const handleKeyDown = (event, index) => {
        if (event.key === "ArrowDown") {
            items[(index + 1) % items.length].current.focus();
        }
        if (event.key === "ArrowUp") {
            items[(index - 1 + items.length) % items.length].current.focus();
        }
    };

    return (
        <div>
            {items.map((ref, i) => (
                <div
                    key={i}
                    ref={ref}
                    tabindex="0"
                    onKeyD own={(e) => handleKeyDown(e, i)}
                >
                    Элемент {i + 1}
                </div>
            ))}
        </div>
    );
});

Особенности подхода:

  • Используется массив useRef для всех фокусируемых элементов.
  • Индексы помогают определить, какой элемент активен, и корректно перемещать фокус.
  • Обеспечивается циклическая навигация, когда стрелка вниз на последнем элементе переводит фокус на первый.

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

Для полноценной поддержки клавиатуры важно использовать атрибуты ARIA. Примеры:

<div role="listbox" aria-activedescendant="item-1">
    <div id="item-1" role="option" tabindex="0">Элемент 1</div>
    <div id="item-2" role="option" tabindex="-1">Элемент 2</div>
</div>

Рекомендации:

  • role="listbox" у контейнера с элементами.
  • role="option" у каждого элемента списка.
  • aria-activedescendant указывает текущий активный элемент.
  • tabindex="-1" на всех неактивных элементах, чтобы фокус перемещался только через программное управление.

Комбинирование клавиш

Atomico позволяет создавать обработку сложных комбинаций:

const handleKeyDown = (event) => {
    if (event.ctrlKey && event.key === "ArrowDown") {
        console.log("Ctrl + стрелка вниз");
    }
};

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


Практические рекомендации

  • Все фокусируемые элементы должны иметь визуальное выделение фокуса через CSS:
div:focus {
    outline: 2px solid #007aff;
}
  • Обработчики клавиатуры лучше регистрировать на контейнере, чтобы не создавать множество отдельных функций на каждом элементе.
  • Использовать useEffect для установки начального фокуса или динамического добавления элементов.
import { useEffect } from "atomico";

useEffect(() => {
    items[0].current.focus();
}, []);
  • Для списков с динамическим контентом рекомендуется отслеживать изменения длины массива и корректировать фокус.

Заключение по подходу

В Atomico навигация с клавиатуры строится на реактивных ссылках, управлении фокусом через tabindex, обработке событий keydown и правильном использовании ARIA-атрибутов. Такой подход обеспечивает:

  • Универсальность на разных компонентах.
  • Простую интеграцию с реактивными состояниями.
  • Поддержку доступности без сторонних библиотек.

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