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

Навигация с клавиатуры является ключевым аспектом доступности веб-приложений. В контексте SvelteKit UI libraries управление фокусом и обработка событий клавиатуры обеспечивают удобный пользовательский интерфейс без необходимости использования мыши. В SvelteKit компоненты можно сделать полностью доступными с помощью встроенных событий и специальных атрибутов.

Атрибуты для управления фокусом

  1. tabindex Позволяет контролировать порядок фокусировки элементов.

    • tabindex="0" – элемент доступен в обычном порядке табуляции.
    • tabindex="-1" – элемент доступен для фокусировки программно, но пропускается при обычной навигации.
    • tabindex="n" (n > 0) – задаёт конкретный порядок фокусировки, но использование чисел больше 0 не рекомендуется для динамических интерфейсов из-за сложности поддержки.
  2. autofocus Автоматически ставит фокус на элемент при рендеринге компонента. Используется для форм или модальных окон.

Обработка событий клавиатуры

SvelteKit позволяет обрабатывать события клавиатуры напрямую через стандартные DOM-события: keydown, keyup, keypress. На практике чаще всего используют keydown, так как оно срабатывает до действия браузера и позволяет предотвратить стандартное поведение.

<script>
  function handleKeyDown(event) {
    if (event.key === "Enter") {
      console.log("Enter нажата");
    } else if (event.key === "ArrowDown") {
      event.preventDefault();
      console.log("Перемещение вниз");
    }
  }
</script>

<input on:keydown={handleKeyDown} />

Компоненты с поддержкой клавиатуры

Большинство библиотек UI для SvelteKit (например, Svelte Material UI, Skeleton UI) предоставляют компоненты с встроенной поддержкой навигации с клавиатуры:

  • Кнопки и ссылки автоматически реагируют на Enter и Space.
  • Модальные окна имеют управление фокусом внутри себя: при открытии фокус устанавливается на первый интерактивный элемент, при закрытии возвращается к предыдущему.
  • Меню и списки поддерживают перемещение стрелками (ArrowUp/ArrowDown) и выбор элементов клавишей Enter.

Пример кастомного меню с клавиатурной навигацией:

<script>
  import { onMount } from 'svelte';
  let items = ["Пункт 1", "Пункт 2", "Пункт 3"];
  let currentIndex = 0;
  let menu;

  function handleKey(event) {
    if (event.key === "ArrowDown") {
      currentIndex = (currentIndex + 1) % items.length;
    } else if (event.key === "ArrowUp") {
      currentIndex = (currentIndex - 1 + items.length) % items.length;
    } else if (event.key === "Enter") {
      console.log(`Выбран: ${items[currentIndex]}`);
    }
  }

  onMount(() => {
    menu.focus();
  });
</script>

<ul bind:this={menu} tabindex="0" on:keydown={handleKey}>
  {#each items as item, i}
    <li class:selected={i === currentIndex}>{item}</li>
  {/each}
</ul>

<style>
  li.selected {
    background-color: #007acc;
    color: white;
  }
</style>

Управление фокусом в динамических интерфейсах

В SvelteKit важно корректно управлять фокусом при изменении DOM, особенно в интерактивных компонентах:

  • bind:this позволяет ссылаться на элемент и программно устанавливать фокус.
  • tick() из svelte используется для ожидания рендера перед установкой фокуса.
<script>
  import { tick } from 'svelte';
  let input;

  async function focusInput() {
    await tick();
    input.focus();
  }
</script>

<input bind:this={input} />
<button on:click={focusInput}>Фокус на поле</button>

События управления доступностью

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

  • aria-selected для выделенных элементов.
  • aria-expanded для раскрывающихся списков.
  • role="menu" и role="menuitem" для меню и пунктов меню.

Это позволяет вспомогательным технологиям (экранным читалкам) корректно интерпретировать состояние интерфейса и обеспечивать навигацию с клавиатуры.

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

SvelteKit UI libs часто предоставляют утилиты для управления фокусом между компонентами:

  • focusable – возвращает массив всех интерактивных элементов.
  • focusNext / focusPrev – перемещает фокус по порядку.

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

<script>
  import { focusNext, focusPrev } from 'sveltekit-ui-utils';
  
  function handleTab(event) {
    if (event.key === "Tab" && !event.shiftKey) {
      event.preventDefault();
      focusNext(event.target);
    } else if (event.key === "Tab" && event.shiftKey) {
      event.preventDefault();
      focusPrev(event.target);
    }
  }
</script>

<form on:keydown={handleTab}>
  <input placeholder="Имя" />
  <input placeholder="Email" />
  <button type="submit">Отправить</button>
</form>

Рекомендации по улучшению UX клавиатурной навигации

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

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