← Back to blog

JavaScript Accessibility Cheat Sheet for Everyday UI Work

Build accessible JavaScript features faster with a practical checklist, patterns, and a central cheat sheet you can keep open while you code.

Why this cheat sheet exists

JavaScript is often where accessibility wins (or regressions) happen: focus moves, ARIA updates, keyboard handling and dynamic content all live here. The goal of this post is simple: keep a compact, actionable reference nearby so your UI behavior works for keyboard, screen reader and touch users.

Below is the core cheat sheet. Everything else in this post expands on it with examples and small reminders.

Accessibility cheat sheet (keep this table open)

ScenarioJavaScript taskAccessibility cueSnippet / reminder
Open a modalMove focus into the modal and trap itFocus should land on the modal title or first control
Code
dialogEl.focus();
+ loop focus within
Code
[tabindex], button, input, a
Close a modalRestore focus to the openerUsers should return to where they were
Code
opener.focus();
after
Code
close()
Toggle a disclosureUpdate aria-expanded and hiddenScreen readers rely on state changes
Code
button.setAttribute('aria-expanded', isOpen); panel.hidden = !isOpen;
Build custom buttonsUse
Code
button
element or add keyboard support
Space/Enter should activate
Code
el.addEventListener('keydown', onActivate)
Update live contentAnnounce new informationUse
Code
aria-live
regions sparingly
Code
<div aria-live="polite">
for status text
Validate a formLink errors to inputsUse
Code
aria-invalid
+
Code
aria-describedby
Code
field.setAttribute('aria-invalid', 'true')
Dynamic listsPreserve selection and keyboard navAvoid focus loss on rerenderKeep
Code
tabindex="0"
on active item
Skip linksReveal on focus and scrollProvide a fast route to main content
Code
skipLink.focus(); main.scrollIntoView()
Infinite scrollOffer a “Load more” fallbackContinuous scroll can trap users
Code
button.hidden = false
on
Code
IntersectionObserver
TooltipShow on focus + hoverKeyboard users need access
Code
trigger.addEventListener('focus', show)
CarouselPause, play, and announceMotion should be user-controlledAdd pause button +
Code
aria-live="off"
Drag and dropProvide keyboard alternativeDragging alone is not enoughOffer move up/down buttons

Key principles before you write code

  1. Native elements first. If you can use <button>, <details>, or <dialog>, do it. You get keyboard handling and semantics for free.
  2. Focus is a feature. Any time you open, close, or reorder UI, ask: Where should focus go next?
  3. State must be perceivable. If something expands, collapses, or changes state, reflect it in ARIA or visible text.
  4. Keyboard parity. Everything you can click should be operable with Tab + Enter/Space.

Patterns you can copy

Accessible disclosure component

Code
const button = document.querySelector('[data-disclosure-button]');
const panel = document.querySelector('[data-disclosure-panel]');

button.addEventListener('click', () => {
  const isOpen = button.getAttribute('aria-expanded') === 'true';
  button.setAttribute('aria-expanded', String(!isOpen));
  panel.hidden = isOpen;
});

Checklist: aria-expanded updates, panel uses hidden and the button remains a real <button> element.

Focus management for modal dialogs

Code
const dialog = document.querySelector('[data-dialog]');
const openButton = document.querySelector('[data-dialog-open]');
const closeButton = dialog.querySelector('[data-dialog-close]');

openButton.addEventListener('click', () => {
  dialog.showModal();
  closeButton.focus();
});

closeButton.addEventListener('click', () => {
  dialog.close();
  openButton.focus();
});

If you cannot use <dialog>, mirror the behavior: add role="dialog", trap focus within the modal and restore focus to the opener when closed.

Live region for async status updates

Code
const status = document.querySelector('[data-status]');

function notify(message) {
  status.textContent = '';
  requestAnimationFrame(() => {
    status.textContent = message;
  });
}

Use a div with aria-live="polite" so screen readers announce updates without taking over.

Common pitfalls and quick fixes

  • Pitfall: Adding onClick to a <div> without keyboard support.
    Fix: Use a <button> or add tabindex="0", plus Enter/Space handlers.
  • Pitfall: Triggering a dropdown but not telling assistive tech.
    Fix: Add aria-expanded to the trigger and toggle it on click.
  • Pitfall: Rerendering a list and losing focus.
    Fix: Keep focus on the selected item and restore it after DOM updates.

How to use this in daily work

  • Paste the cheat sheet into your project notes or wiki.
  • Run through it when you add a new interactive component.
  • Pair it with a quick keyboard pass (Tab, Shift+Tab, Enter, Space, Escape).

Final takeaway

Accessibility is not a separate project; it is a set of tiny decisions. If you can remember to manage focus, keep keyboard parity, and announce state changes, your JavaScript will already outperform most production UIs. Keep the table handy, and you will ship inclusive features faster.