CSS is Awesome

Accessibility

Accessibility is a default, not a feature — the system ships the primitives; this page shows where they live.

Focus rings

The focus-ring mixin in scss/_mixins.scss is the single source of truth for visible keyboard focus. It targets :focus-visible (so mouse clicks never light up a button mid-press) and draws a 3-pixel ring in var(--border-focus), which every theme overrides to a colour that passes WCAG contrast against its own background. Pass a non-zero $offset and the mixin switches from a box-shadow ring to a real outline with outline-offset — useful when an element has its own shadow you do not want the ring to fight with.

// signature
@mixin focus-ring($color: border-focus, $width: 3px, $offset: 0);

// usage on a custom element
.my-link {
  @include m.focus-ring;
}

// with outline-offset for elements that already cast a shadow
.chip {
  @include m.focus-ring($offset: 2px);
}

Every interactive cia component — Button, Input, Select, Tabs, Dropdown, the dismiss control inside Alert — already includes focus-ring through its base mixin. You only need to call it yourself on bespoke interactive elements you compose outside the component set.

Colour contrast

Status tokens — --success-default, --warning-default, --error-default, --info-default — are defined in every one of the six shipped themes and are tuned so that text set in the token reaches WCAG AA (4.5:1 for body copy, 3:1 for large text) against its intended surface. The same holds for --text-default against --surface-default and --border-focus against whatever component it wraps. See /docs/tokens#palette for the full token gallery per theme.

Payment received

We processed your order and emailed a receipt.
<Alert status="success" title="Payment received">
  We processed your order and emailed a receipt.
</Alert>

<Alert status="error" title="Could not save">
  The server rejected three of the nine fields.
</Alert>

Screen-reader-only text

The .cia-sr-only utility hides content visually while keeping it in the accessibility tree, so assistive technology still announces it. Use it to label icon-only controls, annotate decorative layout, or expose headings that a sighted user gets from visual structure. A matching .cia-not-sr-only utility reverses the effect — useful for skip links that should appear on focus.

/* from scss/_utilities.scss */
.cia-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}
<button class="cia-btn-ghost">
  <span aria-hidden="true">×</span>
  <span class="cia-sr-only">Close dialog</span>
</button>

A parallel @mixin sr-only lives in scss/_mixins.scss when you would rather compose the same declarations into your own class.

Keyboard navigation

Every interactive cia React component — Tabs, Dropdown, Modal, Tooltip, DataTable, Accordion — ships with keyboard handling wired up: arrow keys for roving tab-index inside menus and tablists, Escape to close overlays, Enter and Space to activate. For custom interactive elements you build yourself, reach for native <button>, <a href> or <input> before writing a <div onClick> — the browser gives you focus management, keyboard activation and correct role for free.

When you genuinely need a custom widget pattern (a split button, a command palette, a combobox), the WAI-ARIA Authoring Practices documents every pattern with the keyboard interaction model you are expected to match.

ARIA patterns

Each high-level cia component implements a named pattern from the Authoring Practices Guide. The table below maps them so you know exactly what behaviour is already covered.

ComponentPattern
<Modal>Dialog, with focus trap and restore on close
<Tabs>Tabs, with arrow-key navigation between tabs
<Dropdown>Menu, with Escape to close and arrow keys to move
<Tooltip>Tooltip, linked to its target with aria-describedby
<Accordion>Disclosure, one button per collapsible region

Prefers-reduced-motion

Every animation shipped in the system is wrapped in a @media (prefers-reduced-motion: reduce) guard that shortens durations to near-zero and skips non-essential transforms. See /docs/animation#reduced-motion for the implementation and the mixins that honour the preference automatically.

Skip to content

Recommendation. The current SiteHeader does not yet include a skip link. A standard implementation pairs .cia-sr-only with .cia-not-sr-only on focus, so the link is invisible until a keyboard user tabs onto the first focusable element of the page. Target the page's main landmark by id.

<!-- first element inside <body>, before the header -->
<a class="cia-sr-only focus:cia-not-sr-only" href="#main">
  Skip to content
</a>

<!-- ... header, nav ... -->

<main id="main">
  <!-- page content -->
</main>

If you are writing the CSS yourself rather than composing utilities, the minimal rule is: absolutely position the link off-screen, then reveal it with :focus or :focus-visible.

Writing accessible components

Theme