Accessibility Basics
Making interactive elements work for keyboard users and screen readers by choosing semantic HTML first.
Accessibility means a feature works for users who are blind, cannot use a mouse, or navigate with a keyboard or screen reader. The web platform handles most of this automatically when you use semantic HTML and leave keyboard behavior intact.
Semantic elements carry behavior. A <button> is focusable, exposes the correct role, and activates with Enter or Space. A link with href is focusable and activates with Enter. A clickable <div> has none of that, so it starts broken for keyboard and screen reader users.
<!-- Native: role, focus, Enter, and Space all work without JavaScript glue -->
<button type="button" onclick="deleteItem()">Delete</button>
<!-- Fake button: click-only unless you rebuild native button behavior -->
<div onclick="deleteItem()">Delete</div>
<!-- If a custom widget is truly unavoidable, it needs the missing semantics -->
<div class="fake-delete" role="button" tabindex="0" onclick="deleteItem()">Delete</div>// Only do this when a native element cannot express the interaction.
const fakeButton = document.querySelector(".fake-delete");
fakeButton.addEventListener("keydown", (event) => {
if (event.key === "Enter") {
deleteItem();
}
if (event.key === " ") {
event.preventDefault(); // prevent the page from scrolling
}
});
fakeButton.addEventListener("keyup", (event) => {
if (event.key === " ") {
deleteItem(); // Space activates native buttons on release
}
});In production
If a feature only works with a mouse, it ships broken. Keyboard support is part of the baseline web contract, not an enhancement. Keep visible :focus-visible styles, prefer native elements, and test by tabbing through the feature without a mouse. ARIA is the patch layer for cases where native semantics do not reach, such as custom tabs or comboboxes. Reach for ARIA only after native elements fail you, because incorrect ARIA can make the accessibility tree worse than plain HTML.