Svelte 53: Accessibility Basics
easy⏱ 5 mincoursesvelte
role, aria-* and tabindex on custom controls
A <div> isn't a <button> — it gets no keyboard focus and no accessible role by default. To turn one into a real custom control, add role="switch" (or button/checkbox), aria-checked (or aria-pressed) reflecting current state, tabindex="0" so Tab can reach it, and an onkeydown handler for Enter and Space, since only <button> gets those for free.
<div
role="switch"
aria-checked={on}
tabindex="0"
onclick={toggle}
onkeydown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
toggle();
}
}}
>
{on ? 'On' : 'Off'}
</div>
aria-live announces without stealing focus
An element with aria-live="polite" is watched by screen readers: whenever its text content changes, it gets announced — without moving the user's keyboard focus away from whatever they were doing. That's exactly what you want for toast messages, counters, and status updates.
Prefer the real element when one exists
This lesson builds a custom switch to teach the underlying mechanics — but in real code, reach for a native <button> or <input type="checkbox"> first. They get focus, keyboard handling, and correct semantics for free, with far less code and fewer ways to get it wrong.