Keyboard shortcuts

Tab
Navigate between interactive elements
Shift + Tab
Backward navigation
Entrée / Espace
Activate buttons and links
Échap
Close modals and menus
↑ ↓
Navigate in lists and menus

Keyboard navigation in lists

Bad example

Menu with Tab navigation only:

<!-- Bad: Tab navigation only -->
<div class="menu">
  <div tabindex="0">🏠 Home</div>
  <div tabindex="0">📋 Projects</div>
  <div tabindex="0">👥 Team</div>
  <div tabindex="0">📊 Stats</div>
  <div tabindex="0">⚙️ Settings</div>
</div>

<!-- User must Tab 5 times -->
<!-- No arrow navigation -->
<!-- No menu semantics -->

Good example

Menu with arrow navigation:

💡 Use ↑ ↓ to navigate, Enter to select

<!-- Good: arrow navigation with roving tabindex -->
<div
  role="menu"
  @keydown="handleKeydown"
>
  <div
    v-for="(item, i) in items"
    role="menuitem"
    :tabindex="selected === i ? 0 : -1"
    @focus="selected = i"
    :class="{ selected: selected === i }"
  >
    {{ item }}
  </div>
</div>
// Arrow navigation with roving tabindex
function handleKeydown(e) {
  switch(e.key) {
    case 'ArrowDown':
      selected = (selected + 1) % items.length
      break
    case 'ArrowUp':
      selected = selected === 0
        ? items.length - 1
        : selected - 1
      break
    case 'Enter':
      selectItem(selected)
      break
  }
}

Explanation: Keyboard navigable lists allow using arrow keys to move between elements, in addition to classic Tab navigation.

Visible focus styles

Bad example

Try navigating with Tab in this area:

Link to page
/* ❌ Removes all focus indicators */
*:focus {
  outline: none !important;
}

button:focus,
a:focus,
input:focus {
  outline: none !important;
}
<!-- ❌ Accessibility problems: -->
<button>Button 1</button>        <!-- No type, invisible focus -->
<button>Button 2</button>        <!-- No type, invisible focus -->
<a href="#">Link</a>           <!-- Invisible focus -->
<input type="text" />         <!-- Invisible focus -->

<!-- Keyboard navigation impossible to follow visually -->

Good example

Try navigating with Tab in this area:

Link to page
/* ✅ Visible and accessible focus indicators */
button:focus-visible {
  outline: 3px solid #4F46E5;
  outline-offset: 2px;
}

input:focus-visible {
  border-color: #4F46E5;
  outline: 2px solid #4F46E5;
  outline-offset: 1px;
}
<button type="button">Button 1</button>
<button type="button">Button 2</button>
<a href="#">Link to page</a>
<input type="text" placeholder="Enter text" />

Explanation: Users navigating with keyboard need clear visual indicators to know where they are on the page.

Skip link (Skip to content)

Bad example

Main content

The user must navigate through all navigation links...

<!-- Bad: no skip link -->
<header>
  <nav>
    <a href="#">Home</a>
    <a href="#">Products</a>
    <a href="#">Services</a>
    <!-- 10+ navigation links... -->
  </nav>
</header>
<main>
  <!-- User must traverse all navigation -->
  <h1>Main content</h1>
</main>

Good example

Main content

The user can access directly here thanks to the skip link!

/* Skip link hidden by default, visible on focus */
.skip-link {
  position: absolute;
  top: -100px;
  left: 1rem;
  z-index: 1000;
  padding: 0.5rem 1rem;
  background: var(--color-primary);
  color: white;
  text-decoration: none;
  border-radius: 0.625rem;
}

.skip-link:focus {
  top: 1rem;
}
<a href="#main-content" class="skip-link">
  Skip to main content
</a>
<header>
  <nav aria-label="Main navigation">
    <ul>
      <li><a href="/">Home</a></li>
      <li><a href="/produits">Products</a></li>
      <li><a href="/services">Services</a></li>
    </ul>
  </nav>
</header>
<main id="main-content">
  <h1>Main content</h1>
</main>

Explanation: Skip links allow keyboard users to jump directly to the main content without having to go through all the navigation.

Modal with focus trap

Bad example

Good example

Explanation: Modals must keep focus inside and allow closing with the Escape key. Focus must return to the element that opened the modal.