Keyboard Navigation
19.3.1. Focus Management
All interactive UI elements must be accessible and operable via keyboard. The tabindex attribute must be used according to the following rules.
| tabindex Value | Meaning | Usage Rules |
|---|---|---|
0 | Included in the natural Tab order | Used to make non-interactive elements focusable |
-1 | Excluded from Tab order, focusable programmatically | Used to move focus via script in modals, dynamic content, etc. |
Positive (1 or higher) | Prohibited | Arbitrarily alters Tab order, causing unpredictable behavior |
- Native interactive elements such as
<button>,<a>, and<input>receive focus by default, sotabindexmust not be specified separately for them. - Binding click events to non-interactive elements such as
<div>and<span>should be avoided. Use<button>elements instead.
A focus indicator (Focus Ring) must be visually displayed on all focusable elements.
css
/* Default focus indicator style */
:focus-visible {
outline: 2px solid #2563eb;
outline-offset: 2px;
}
/* Removing outline is prohibited */
/* Incorrect example: *:focus { outline: none; } */- The focus indicator must not be removed with
outline: none.outline: nonemay be used only when replacing with a custom style, and an equivalent visual indicator must be provided. - Using
:focus-visibleto apply the indicator only to keyboard focus is recommended.
19.3.2. Tab Order
The order of Tab key navigation must follow the logical flow and visual layout order of the content.
- The DOM order must match the visual order. Changing only the visual order with CSS properties such as
order,flex-direction: row-reverse, andposition: absolutecauses a mismatch with the Tab order. - When layout must be rearranged with CSS, the DOM order itself must be changed to maintain the logical flow.
- Dynamically inserted content (toasts, dropdowns, etc.) must be positioned so as not to disrupt the Tab order.
vue
<!-- Correct: DOM order = Visual order -->
<template>
<nav>
<a href="/home">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
<main>
<h1>Page Title</h1>
<p>Body content</p>
</main>
</template>
<!-- Incorrect: Only visual order reversed via CSS -->
<!--
<template>
<div class="flex flex-row-reverse">
<button>Appears first but Tab order is last</button>
<button>Appears last but Tab order is first</button>
</div>
</template>
-->19.3.3. Keyboard Shortcuts
Interactive components must support the following keyboard actions.
| Key | Action | Applicable To |
|---|---|---|
Enter | Button click, form submit, link activation | Buttons, forms, links |
Escape | Close modal, close dropdown, cancel action | Modals, dropdowns, popovers |
Space | Toggle checkbox, button click | Checkboxes, buttons |
| Arrow keys | Switch tab panels, navigate menu items, select radio buttons | Tabs, menus, radio groups |
vue
<script setup lang="ts">
import { ref } from 'vue'
const isOpen = ref(false)
function handleKeydown(event: KeyboardEvent) {
if (event.key === 'Escape') {
isOpen.value = false
}
}
</script>
<template>
<div @keydown="handleKeydown">
<button @click="isOpen = !isOpen">
Open Menu
</button>
<ul v-if="isOpen" role="menu">
<li role="menuitem" tabindex="0">Item 1</li>
<li role="menuitem" tabindex="0">Item 2</li>
<li role="menuitem" tabindex="0">Item 3</li>
</ul>
</div>
</template>- Keyboard actions must be handled with
@keydownevents.@keypressmust not be used. - Using Vue's key modifiers (
@keydown.escape,@keydown.enter) is recommended. - When providing custom keyboard shortcuts, they must not conflict with browser and operating system default shortcuts.
19.3.4. Skip Navigation
A skip navigation link must be provided to bypass repetitive navigation areas and jump directly to the main content.
vue
<template>
<a
href="#main-content"
class="skip-nav"
>
Skip to main content
</a>
<header>
<nav>
<!-- Navigation items -->
</nav>
</header>
<main id="main-content" tabindex="-1">
<!-- Main content -->
</main>
</template>
<style scoped>
.skip-nav {
position: absolute;
top: -100%;
left: 0;
z-index: 9999;
padding: 8px 16px;
background-color: #ffffff;
color: #1a1a1a;
font-weight: bold;
text-decoration: none;
}
.skip-nav:focus {
top: 0;
}
</style>- The skip navigation link must be placed as the first element at the very top of the page.
- It must be hidden from view by default and displayed on screen only when it receives focus.
tabindex="-1"must be specified on the link target (#main-content) to enable it to receive focus.- When the navigation area is complex, additional shortcut links to the search area or sidebar may be provided.