ARIA and HTML5 Accessibility for Web Games
The First Rule: Use Semantic HTML Before ARIA
ARIA is a supplement to HTML, not a replacement. The first rule of ARIA, stated by the W3C itself, is: "If you can use a native HTML element with the semantics and behavior you require already built in, instead of re-purposing an element and adding an ARIA role, state or property to make it accessible, then do so." Native HTML elements like button, a, input, select, h1-h6, nav, main, dialog, and details have built-in accessibility: screen readers announce their roles, keyboard interaction works automatically, and state management is handled by the browser.
A game menu built with button elements for each option, wrapped in a nav element with heading elements for section titles, is already accessible with zero ARIA. A settings screen using native input elements (range sliders, checkboxes, radio buttons, text inputs) is already accessible. A dialogue box using the dialog element with showModal() handles focus trapping and screen reader announcements automatically. Use these elements first. Add ARIA only when the native element does not exist for the pattern you need (e.g., a custom tabbed interface, a drag-and-drop inventory grid, or a live game state display).
Game Menu Patterns
A main menu is a vertical list of navigation options. The simplest accessible implementation is a nav element containing button elements. Each button represents a menu action (Play, Settings, Credits, Quit). Screen readers announce "navigation" when entering the nav, then "Play, button" for each option. Keyboard users Tab between buttons and press Enter or Space to activate.
For a multi-level menu (main menu with submenus), use aria-expanded on the button that opens a submenu. When the submenu is collapsed, the button has aria-expanded="false." When expanded, it switches to aria-expanded="true." The screen reader announces "Settings, button, collapsed" or "Settings, button, expanded," telling the user whether the submenu is visible. The submenu itself can be a div with role="menu" containing elements with role="menuitem," which tells the screen reader to use menu navigation behavior (arrow keys move between items instead of Tab).
For in-game radial menus or grid-based menus that do not map to a linear list, use role="menu" on the container and role="menuitem" on each option. Manage focus within the menu using arrow key handlers: up/down arrows or left/right arrows move focus between items. This replicates the keyboard behavior that screen reader users expect from a menu component. When the menu closes, return focus to the element that opened it.
Inventory and Item Grid Patterns
An inventory screen with a grid of item slots maps to the ARIA grid pattern. Use role="grid" on the container, role="row" for each row, and role="gridcell" for each cell. Each cell contains either an item (with an aria-label describing the item: "Healing Potion, quantity 3") or is empty (with aria-label="Empty slot"). The grid pattern supports arrow key navigation: up/down moves between rows, left/right moves between cells in a row.
When a player selects an item, set aria-selected="true" on the selected cell and aria-selected="false" on all others. If selecting an item opens a context menu (Use, Drop, Equip), focus the context menu and announce its options. When the context menu closes, return focus to the selected item cell.
For drag-and-drop inventory rearrangement, provide a keyboard alternative. When a player presses Enter or Space on an item, enter a "pick up" mode (announce "Picked up Healing Potion, use arrow keys to move, press Enter to place"). Arrow keys move the item to adjacent cells. Enter drops it in the current cell. Escape cancels and returns the item to its original position. This keyboard interaction replicates the drag-and-drop flow without requiring mouse precision.
Dialogue and Text Display Patterns
Game dialogue boxes, whether for NPC conversation, narrative text, or tutorial instructions, should use the HTML dialog element when possible. The dialog element with showModal() automatically traps focus, provides Escape-to-close behavior, and is announced as a dialog by screen readers. Set aria-labelledby on the dialog pointing to the heading or speaker name element, so the screen reader announces "Dialog, Elena says" when the dialog opens.
For dialogue choices (multiple response options), use button elements for each choice. Focus the first choice button when the dialogue opens. Let arrow keys move between choices and Enter select one. Announce the result of the choice through the dialogue text that follows. If dialogue auto-advances on a timer, provide a setting to disable auto-advance (critical for players who use screen readers, because they need time for the screen reader to read the text).
For long narrative text or scrollable text areas, use a div with role="log" or role="status" for content that updates over time (like a chat log or quest log). Mark the container with aria-live="polite" so new entries are announced as they appear. For static scrollable text (credits, lore entries, help text), a simple div with tabindex="0" and overflow: auto is sufficient; the user can scroll with arrow keys when the element has focus.
HUD and Overlay Patterns
The game HUD (heads-up display) overlays information on the game canvas: health, score, minimap, ammo, timer, and other persistent indicators. For screen reader accessibility, these elements need to be present in the DOM (not rendered only on the canvas) with appropriate ARIA attributes.
Create a HUD container with role="status" and aria-label="Game status." Inside, place individual elements for each HUD value: a span with aria-label="Health: 75 out of 100" that updates when health changes, a span with aria-label="Score: 1500" that updates on score change, and similar elements for other values. Set aria-live="polite" on elements that should be announced when they change, and aria-live="off" on elements that change too frequently (like a real-time frame counter).
For urgent HUD changes (health critically low, timer running out), use aria-live="assertive" to interrupt the screen reader. But use this sparingly: if every health change is assertive, the screen reader will constantly interrupt gameplay announcements. A practical approach is to use aria-live="polite" for routine updates and switch to "assertive" only when a value crosses a critical threshold (health below 25%, timer below 10 seconds).
The minimap is a visual representation that has no direct screen reader equivalent. For screen reader users, provide a text summary of nearby points of interest: "3 enemies to the north, quest marker 50 meters east, safe zone to the south." Update this summary periodically (every few seconds, not every frame) in a live region. This gives screen reader users spatial awareness without requiring them to see the minimap.
Canvas-HTML Hybrid Architecture
Most web games use a hybrid architecture: the game world renders on a canvas element (2D Canvas or WebGL), while UI overlays are built in HTML/CSS positioned on top of the canvas. This architecture is inherently accessibility-friendly because the HTML layer is accessible to assistive technologies while the canvas handles the visual rendering that assistive technologies cannot interpret.
The canvas element itself should have a descriptive aria-label: "Game canvas, use keyboard controls to play." If the game is primarily turn-based or text-based, consider adding a role="application" to the canvas to tell screen readers that it is an interactive application rather than a static image. This changes how screen readers pass keyboard input: in application mode, all keystrokes go directly to the application instead of being intercepted by the screen reader for navigation.
When the game transitions between states (gameplay to menu, gameplay to dialogue, gameplay to inventory), manage focus between the canvas and the HTML overlays. During gameplay, focus should be on the canvas or a surrounding container so keyboard input reaches the game. When a menu opens, focus moves to the menu (the canvas continues rendering but input goes to the menu). When the menu closes, focus returns to the canvas. This focus switching is the glue that holds the hybrid architecture together for accessibility.
Avoid rendering UI text on the canvas if it can be rendered in HTML instead. Canvas text is invisible to screen readers, cannot be selected, does not scale with browser zoom, and does not benefit from CSS typography features. Health bars, scores, dialogue, menus, tooltips, notifications, and any other text-based UI should be HTML elements positioned over the canvas with CSS. Reserve the canvas for game world rendering, where screen readers cannot help regardless of implementation.
Media Queries for Accessibility Preferences
CSS media queries let web games detect and respect operating system accessibility preferences automatically. The most relevant queries for games are:
prefers-reduced-motion: detects when the user has enabled "Reduce motion" in their OS settings. Check this with window.matchMedia('(prefers-reduced-motion: reduce)').matches and use it to default your game's motion settings to reduced. Disable or reduce screen shake, particle effects, parallax scrolling, and rapid camera movements.
prefers-contrast: detects when the user has enabled a high-contrast mode. Apply a high-contrast stylesheet to your HTML UI: thicker borders, higher contrast colors, and bolder text. Values are "more" (wants higher contrast) and "less" (wants lower contrast).
prefers-color-scheme: detects light or dark mode preference. If your game menus have a theme option, default to matching the OS preference. This is less about accessibility and more about user comfort, but it contributes to a polished experience.
forced-colors: detects Windows High Contrast Mode, which overrides all colors with a user-defined palette. In this mode, your CSS colors are replaced, and you should ensure that borders, focus indicators, and text remain visible. Test your UI with Windows High Contrast Mode enabled to verify nothing disappears.
Build game UI with semantic HTML first, add ARIA only for custom components, render all text and UI in HTML (not on the canvas), manage focus between the canvas and HTML overlays when game states change, and respect OS accessibility preferences through CSS media queries. This architecture gives web games a significant accessibility advantage over native games.