フォーカスインジケーターとキーボード操作
ring ユーティリティで視認性の高いフォーカススタイルを適用し、focus-visible でクリック時の不要なフォーカス表示を避け、すべての操作要素をキーボードで操作できるようにします。
「フォーカスインジケーターとキーボード操作」はCoddyKit上の無料Tailwind CSS Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはTailwind CSS Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Tailwind CSS Academyコースには全4レッスンが含まれています。
このレッスンの一部はまだ翻訳されておらず、英語で表示されています。
Why Keyboard Navigation Matters
Not all users navigate with a mouse. Users with motor disabilities rely on keyboards, switch controls, or voice navigation. Power users prefer keyboard shortcuts for efficiency. Screen reader users navigate primarily with the keyboard. WCAG 2.4.3 Focus Order requires all functionality to be operable via keyboard, and WCAG 2.4.7 requires that keyboard-focused elements have a visible focus indicator. Tailwind provides utilities to implement both requirements.
Default Focus Styles and Their Problems
Browsers provide default focus indicators (typically a blue outline), but many designers remove them globally with outline: none or outline: 0 because they appear on mouse clicks too. This is an accessibility disaster — removing the outline means keyboard users have no visual cue showing which element has focus. Tailwind's modern approach distinguishes between mouse focus and keyboard focus using the focus-visible pseudo-class.
/* NEVER do this globally */
* {
outline: none; /* destroys keyboard accessibility */
}
/* WRONG approach in Tailwind */
<button class='focus:outline-none'>...</button>
/* Removes focus for keyboard users too */
/* BETTER: suppress only for mouse users */
<button class='focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500'>
This button shows ring for keyboard users only
</button>Tailwind's focus-visible Variant
The focus-visible: variant targets the :focus-visible CSS pseudo-class, which the browser applies when focus was received via keyboard navigation (Tab, arrow keys) but NOT when focus was received via mouse click. This is exactly what designers want — no focus ring on mouse click, but a clear ring when tabbing. Use focus-visible:ring-2 focus-visible:ring-blue-500 as a standard focus style for interactive elements.
<!-- Standard button with focus-visible ring -->
<button
class='
px-4 py-2 bg-blue-600 text-white rounded-lg font-medium
focus:outline-none
focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2
'
>
Submit
</button>
<!-- Link with focus-visible style -->
<a
href='/docs'
class='
text-blue-700 underline
focus:outline-none
focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-1 focus-visible:rounded
'
>
Documentation
</a>Ring Utilities for Focus Indicators
Tailwind's ring-* utilities create a CSS box-shadow-based outline that appears outside the element's border without affecting layout. ring-2 sets a 2px ring, ring-blue-500 sets its color, and ring-offset-2 adds a 2px gap between the element's border and the ring, creating a clear separation that makes the focus indicator more visible on colored backgrounds.
<!-- Ring width options -->
<button class='ring-1 ...'>1px ring</button>
<button class='ring-2 ...'>2px ring (recommended)</button>
<button class='ring-4 ...'>4px ring (high visibility)</button>
<!-- Ring with offset (recommended for buttons) -->
<button class='focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2'>
With offset gap
</button>
<!-- Ring offset on dark background -->
<div class='bg-gray-900 p-4'>
<button class='
bg-blue-600 text-white px-4 py-2 rounded
focus-visible:ring-2 focus-visible:ring-blue-400
focus-visible:ring-offset-2 focus-visible:ring-offset-gray-900
'>Dark bg button</button>
</div>Tab Order and tabindex
The keyboard Tab order should follow the visual reading order of the page (top to bottom, left to right in LTR layouts). Use semantic HTML elements like button, a, and input that are natively focusable in the correct order. Avoid using tabindex to force unnatural focus orders. Use tabindex='0' to make a non-interactive element (like a custom component) keyboard focusable, and tabindex='-1' to remove an element from the tab sequence while keeping it programmatically focusable.
<!-- Native elements: in tab order automatically -->
<button>First</button> <!-- tab stop 1 -->
<a href='/'>Second</a> <!-- tab stop 2 -->
<input type='text' /> <!-- tab stop 3 -->
<!-- Custom component: add to tab order with tabindex='0' -->
<div
role='button'
tabindex='0'
class='focus-visible:ring-2 focus-visible:ring-blue-500'
onKeyDown={(e) => e.key === 'Enter' && handleClick()}
>
Custom interactive element
</div>
<!-- Remove from tab order but allow programmatic focus -->
<div tabindex='-1' ref={modalPanelRef}>
Modal content (focused by JS, not Tab)
</div>Focus Management in SPAs
In Single Page Applications, route changes and dynamic content updates do not trigger a page reload, so the browser does not reset focus. After navigation, programmatically move focus to the new page's main heading or skip-link target. After a modal opens, move focus inside it. After it closes, return focus to the triggering element. Use React's useRef and element.focus() to implement these patterns.
// Focus management after route change (React/Next.js)
import { useEffect, useRef } from 'react';
import { usePathname } from 'next/navigation';
function MainContent({ children }) {
const mainRef = useRef(null);
const pathname = usePathname();
useEffect(() => {
// Move focus to main content on route change
mainRef.current?.focus();
}, [pathname]);
return (
<main
ref={mainRef}
tabIndex={-1} // focusable but not in tab order
className='focus:outline-none'
>
{children}
</main>
);
}Skip Navigation Links
A skip navigation link is a visually hidden link at the top of the page that becomes visible when focused, allowing keyboard users to jump directly to the main content area without tabbing through all navigation links. This is required by WCAG 2.4.1 (Bypass Blocks). Tailwind's sr-only and focus:not-sr-only (or focus:ring) utilities implement this elegantly.
<!-- Skip nav: hidden until focused by keyboard -->
<a
href='#main-content'
class='
sr-only
focus:not-sr-only focus:fixed focus:top-4 focus:left-4 focus:z-50
focus:bg-white focus:text-blue-700 focus:font-semibold
focus:px-4 focus:py-2 focus:rounded-lg focus:shadow-lg
focus:ring-2 focus:ring-blue-500
'
>
Skip to main content
</a>
<nav><!-- navigation --></nav>
<main id='main-content' tabIndex={-1} className='focus:outline-none'>
<!-- page content -->
</main>Arrow Key Navigation Patterns
Some interactive components should respond to arrow keys in addition to Tab. Toolbars and menu bars use left/right arrows to move between items. Select menus and listboxes use up/down arrows. Tab panels use arrow keys to switch tabs. Implementing arrow key navigation in custom components requires JavaScript key event handlers that move focus between related interactive elements.
// Arrow key navigation for a custom tab list
function TabList({ tabs }) {
const tabRefs = useRef([]);
const handleKeyDown = (e, index) => {
let newIndex;
if (e.key === 'ArrowRight') newIndex = (index + 1) % tabs.length;
if (e.key === 'ArrowLeft') newIndex = (index - 1 + tabs.length) % tabs.length;
if (e.key === 'Home') newIndex = 0;
if (e.key === 'End') newIndex = tabs.length - 1;
if (newIndex !== undefined) {
e.preventDefault();
tabRefs.current[newIndex]?.focus();
}
};
return (
<div role='tablist'>
{tabs.map((tab, i) => (
<button
key={tab.id}
ref={el => tabRefs.current[i] = el}
role='tab'
onKeyDown={e => handleKeyDown(e, i)}
className='focus-visible:ring-2 focus-visible:ring-blue-500'
>
{tab.label}
</button>
))}
</div>
);
}High Visibility Focus Styles for Accessibility
WCAG 2.4.11 (Focus Appearance, WCAG 2.2) requires that focus indicators meet minimum size and contrast requirements. A focus ring should be at least 2px thick and have at least a 3:1 contrast ratio against both the focused element and the adjacent background. Tailwind's ring-2 with a suitably contrasting color meets this requirement. For high-contrast mode support, consider using outline instead of box-shadow which Windows High Contrast Mode respects.
/* High contrast mode compatible focus style */
@media (forced-colors: active) {
button:focus-visible,
a:focus-visible,
input:focus-visible {
outline: 3px solid ButtonText;
outline-offset: 2px;
}
}
/* Tailwind equivalent for standard mode */
<button
class='
focus:outline-none
focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600
/* Fallback for High Contrast Mode uses CSS above */
'
>
Accessible button
</button>Testing Keyboard Navigation
Test keyboard navigation manually: put down the mouse entirely and navigate your entire application using only Tab, Shift+Tab, Enter, Space, and arrow keys. Every interactive element should be reachable, every action should be performable, and every focused element should have a visible indicator. Tools like axe DevTools can catch missing focus indicators automatically, but manual testing reveals logical flow issues that automated tools miss.
/*
Keyboard navigation test checklist:
Tab through entire page:
[ ] Every interactive element is reachable
[ ] Every focused element shows a visible indicator
[ ] Tab order follows visual reading order
[ ] No focus traps outside intentional ones (modals)
Activate elements:
[ ] Enter activates buttons and links
[ ] Space activates checkboxes and toggles
[ ] Arrow keys navigate menus, tabs, selects
Modal behavior:
[ ] Focus enters modal on open
[ ] Tab stays inside modal while open
[ ] Escape closes modal
[ ] Focus returns to trigger on close
Automated:
axe-core, Lighthouse accessibility audit
*/Creating a Global Focus Style Baseline
Define a consistent focus style as a global baseline in your CSS rather than repeating it on every element. Use addBase in a Tailwind plugin or add it in the @layer base block of your global CSS. This ensures all natively focusable elements get a consistent, accessible focus indicator by default, and custom components only need to opt in to the same pattern.
/* globals.css — consistent focus baseline */
@layer base {
:focus-visible {
outline: 2px solid #3b82f6; /* blue-500 */
outline-offset: 2px;
border-radius: 0.25rem;
}
/* Remove outline only for mouse users */
:focus:not(:focus-visible) {
outline: none;
}
}
/* Components that need ring instead of outline: */
/* Still override per-element with focus-visible:ring-2 etc. */
<button class='focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500'>Quick Check
Test your understanding of Tailwind CSS Mastery concepts from this lesson.
Lesson Recap
In this lesson you learned: focus-visible: shows focus rings only for keyboard users, ring-2 with ring-offset-2 creates accessible and visually clear focus indicators, and skip navigation links with sr-only allow keyboard users to bypass repetitive navigation. Next up we cover ARIA attributes and how to use Tailwind's sr-only utility for screen reader support.
AI チューターと学ぶ HTML — 無料
ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。
- コース
- 30
- レッスン
- 120
よくある質問
「フォーカスインジケーターとキーボード操作」レッスンは無料ですか?
はい。「フォーカスインジケーターとキーボード操作」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Tailwind CSS Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Tailwind CSS Academyコースには全4レッスンが含まれています。
「フォーカスインジケーターとキーボード操作」で何を学びますか?
ring ユーティリティで視認性の高いフォーカススタイルを適用し、focus-visible でクリック時の不要なフォーカス表示を避け、すべての操作要素をキーボードで操作できるようにします。 ブラウザで直接実行するハンズオンコードでTailwind CSS Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Tailwind CSS Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのTailwind CSS Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「フォーカスインジケーターとキーボード操作」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このTailwind CSS Academyレッスンでコードを書いて実行できますか?
はい。すべてのTailwind CSS Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 色のコントラストと読みやすいテキスト
- フォーカスインジケーターとキーボード操作
- ARIA 属性とスクリーンリーダー
- アクセシブルなフォームコンポーネント