Keyboard Navigation dan Focus Management
Pastikan semua interaksi bisa dilakukan tanpa mouse
Tujuan Pembelajaran
- Bisa membuat UI fully keyboard accessible
- Mengerti focus order dan focus trap
- Mengerti skip links dan landmarks
Analogi
Keyboard Flow:
Tab -> Navigate between elements
Enter/Space -> Activate
Arrow keys -> Navigate within component
Escape -> Close/Dismiss
Keyboard accessibility adalah fondasi aksesibilitas — screen reader user dan power user mengandalkan keyboard
Penjelasan Konsep
Semua interaksi yang bisa dilakukan dengan mouse HARUS bisa dilakukan dengan keyboard. Ini adalah requirement WCAG Level A.
Focus Order
Tab order harus mengikuti visual order (top-to-bottom, left-to-right). Hindari tabindex positif — gunakan tabindex=“0” untuk elemen custom yang perlu focusable, atau tabindex=“-1” untuk programmatic focus.
Visible Focus Indicator
Setiap elemen yang focused harus punya visible indicator (outline). Jangan hapus outline tanpa menggantinya dengan alternatif yang jelas.
Focus Trap
Di dalam modal/dialog, focus harus terjebak — tidak bisa keluar sampai modal ditutup. Radix UI dan shadcn/ui sudah handle ini otomatis.
Skip Link
Link tersembunyi yang memungkinkan screen reader user melewati navigation menu ke konten utama.
Inti yang Perlu Dipahami
Bagian ini berfokus pada bisa membuat UI fully keyboard accessible., mengerti focus order dan focus trap., dan mengerti skip links dan landmarks. Jangan terburu-buru menghafal istilahnya. Lebih penting untuk memahami peran setiap konsep dan kapan konsep itu muncul dalam pekerjaan web development.
Saat membaca Keyboard Navigation dan Focus Management, gunakan tujuan belajar sebagai penanda arah. Kalau kamu sudah bisa menjelaskan tujuan itu dengan kata-katamu sendiri, berarti fondasinya mulai terbentuk.
Cara Membayangkannya
Keyboard accessibility adalah fondasi aksesibilitas — screen reader user dan power user mengandalkan keyboard. Analogi ini dipakai supaya konsep teknis tidak terasa melayang. Hubungkan setiap istilah dengan perannya: siapa yang meminta, siapa yang memproses, data apa yang berpindah, dan hasil apa yang diharapkan.
Kalau analoginya sudah terasa masuk akal, barulah lihat istilah teknisnya. Cara ini membuat materi lebih mudah dipahami daripada langsung menghafal definisi.
Saat Melihat Contoh Kode
Contoh kode pada chapter ini memakai bahasa tsx. Bacalah contoh kode sebagai ilustrasi alur, bukan sebagai bagian yang harus langsung dihafal. sr-only class menyembunyikan visual tapi tetap accessible untuk screen reader. Arrow keys untuk navigate, Escape untuk close dan return focus.
Perhatikan nama fungsi, urutan langkah, dan data yang berpindah. Biasanya tiga hal itu sudah cukup untuk memahami hubungan antara teori dan praktik.
Konteks dalam Perjalanan Belajar
Setiap konsep di platform ini dipilih karena dipakai di industri. Fokus pada pemahaman, bukan hafalan.
Kamu sudah di bagian lanjutan. Mulai pikirkan bagaimana konsep ini dipakai di dunia kerja — bukan hanya untuk belajar, tapi untuk membangun produk nyata.
Gunakan pertanyaan reflektif dan prompt AI di akhir chapter sebagai latihan aktif. Membaca saja tidak cukup — kamu perlu menjelaskan ulang dengan kata-katamu sendiri.
Contoh Kode
// Skip link component
function SkipLink() {
return (
<a href="#main-content"
className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:bg-white focus:px-4 focus:py-2 focus:rounded focus:shadow-lg">
Skip to main content
</a>
);
}
// Keyboard-accessible dropdown
function Dropdown({ items }) {
const [open, setOpen] = useState(false);
const [activeIndex, setActiveIndex] = useState(0);
const btnRef = useRef(null);
const handleKeyDown = (e) => {
if (!open) return;
if (e.key === 'ArrowDown') {
e.preventDefault();
setActiveIndex(i => Math.min(i + 1, items.length - 1));
} else if (e.key === 'ArrowUp') {
e.preventDefault();
setActiveIndex(i => Math.max(i - 1, 0));
} else if (e.key === 'Escape') {
setOpen(false);
btnRef.current?.focus();
}
};
return (
<div onKeyDown={handleKeyDown}>
<button ref={btnRef} onClick={() => setOpen(!open)} aria-expanded={open}>
Options
</button>
{open && (
<ul role="listbox">
{items.map((item, i) => (
<li key={item.id} role="option" aria-selected={i === activeIndex}>
{item.label}
</li>
))}
</ul>
)}
</div>
);
}Penjelasan Kode
Prompt AI
Coba navigasi website-mu hanya dengan keyboard (Tab, Shift+Tab, Enter, Space, Escape). Apakah semua fitur bisa diakses?
Pertanyaan Reflektif
Test dengan screen reader (NVDA gratis untuk Windows, VoiceOver built-in macOS). Dengarkan bagaimana website-mu terdengar.