ilusm.dev

a11y

Accessibility utilities - ARIA attributes, contrast checks, screen reader helpers.

Load with: use a11y

What this module does

a11y gives you functions for building accessible UIs. It generates ARIA attribute objects you can apply to DOM elements, checks whether foreground/background colour combinations meet WCAG contrast standards, and produces screen-reader-only HTML snippets like skip links.

Most functions return a plain object like {aria_label: "Close"} which you spread onto an element. The a11y.X aliases are the public-facing API - use those instead of the raw a11arXX names.

Quick example

use a11y

# Label a button
btn = {tag: "button", attrs: a11y.lbl("Close dialog")}

# Check if text is readable on a background
ok = a11y.ok("#333333", "#ffffff", "AA")
prn(ok)  # tru - passes WCAG AA

# Generate a skip link for keyboard users
skip = a11y.skip("main-content", "Skip to main content")

Functions

ARIA attributes

Each of these returns an object with the appropriate ARIA attribute set. Spread it onto your element.

a11y.role(role)

Sets the ARIA role. E.g. a11y.role("dialog"){role: "dialog"}.

a11y.lbl(label)

Sets aria-label - an invisible label read by screen readers when there's no visible text.

a11y.by(id)

Sets aria-labelledby - points to the ID of another element that acts as the label.

a11y.desc(id)

Sets aria-describedby - points to an element that provides extra description.

a11y.live(val)

Sets aria-live. Use "polite" for updates that wait their turn, "assertive" for urgent ones.

a11y.hide(val)

Sets aria-hidden. Pass tru to hide an element from screen readers entirely. Defaults to "true" if you pass nil.

a11y.exp(val)

Sets aria-expanded - whether a collapsible panel is open. Pass a boolean.

a11y.attr(attrs)

Takes an object of arbitrary ARIA attributes and serialises them to a string of HTML attribute pairs. Underscores in keys are converted to hyphens.

State attributes

Boolean ARIA states - pass tru or fls.

a11sl(val)

Sets aria-selected. Use on tabs, listbox items, or anything selectable.

a11ds(val)

Sets aria-disabled. Marks an element as disabled without removing it from the tab order.

a11rq(val)

Sets aria-required. Use on form fields that must be filled in.

Contrast checking

Check if colour combinations meet WCAG accessibility guidelines. Colours are hex strings like "#ff0000".

a11y.ctr(fg, bg)

Returns the contrast ratio between two colours as a number. 1 is no contrast, 21 is black on white.

a11y.ok(fg, bg, level)

Returns tru if the contrast ratio meets the given WCAG level. Use "AA" (needs 4.5:1) or "AAA" (needs 7:1).

a11lg(fg, bg)

Returns tru if contrast is at least 3:1 - the minimum for large text or UI components under WCAG AA.

Screen reader helpers

a11y.sr(text)

Wraps text in a <span class="sr-only"> - visually hidden but read by screen readers. Use this to add context that's obvious visually but missing for AT users.

a11y.skip(id, text)

Generates a skip link - an anchor that jumps to the element with the given ID. Put this at the top of your page so keyboard users can bypass the navigation.

Focus management

a11tb(val)

Sets tabindex to the given integer. Controls tab order.

a11fo()

Returns {tabindex: "0"} - adds an element to the natural tab order.

a11no()

Returns {tabindex: "-1"} - removes an element from the tab order but keeps it programmatically focusable.

Notes

  • Use the a11y.X aliases (e.g. a11y.role, a11y.lbl) as the public API. The raw a11ar, a11lb etc. names are the implementations.
  • Contrast checking delegates to colr - that module must be available.
  • a11y.attr() is useful when you need to render ARIA attributes as a raw HTML string.