---
title: "Accessibility"
description: "The accessibility requirements Tanrei builds into tokens and component specs, and the checks that enforce them."
url: "https://tanrei.chnotchy.com/foundations/accessibility/"
last_updated: 2026-10-23T17:33:05.000Z
---

# Accessibility

> The accessibility requirements Tanrei builds into tokens and component specs, and the checks that enforce them.

Accessibility in Tanrei is a set of constraints on the system itself. The token build refuses to produce a scheme that fails contrast, and a component spec is not valid without its role, keyboard table and target guarantee.

## Contrast

The token build measures every scheme, light and dark at standard, medium and high contrast, against these thresholds, and fails when a pair falls short:

| Content | Standard and medium contrast | High contrast |
| --- | --- | --- |
| Text, and icons drawn in a content color | 4.5:1 | 7:1 |
| A status’s mark on its own tonal container | 3:1 | 3:1 |
| Boundaries and graphics needed to identify or operate a control | 3:1 | 3:1 |
| The focus ring against adjacent surfaces | 3:1 | 3:1 |

Large text has no lower threshold. WCAG accepts less contrast for text of about 24px regular, or 19px bold, and up, but the build holds every text role at 4.5:1, and at 7:1 at high contrast: a color role does not know the size it will be set in.

Disabled elements and pure decoration are exempt, and so is the `outline-variant` hairline at standard contrast. That exemption is why a border which is the only sign of a control must use `outline`, not `outline-variant`.

### Enforced invariants

These hold for every theme at every contrast level, six permutations in all, and the build fails otherwise:

- each `(X, on-X)` role pair, and each text role (`on-surface`, `on-surface-variant`, `link`, an intent’s color) on every surface role, is at least 4.5:1, and at least 7:1 in the two high-contrast schemes;
- each status color is at least 3:1 against its own tonal container;
- `outline` is at least 3:1 against every surface role;
- in the default system at medium and high contrast, `outline-variant` is at least 3:1 and 4.5:1 against every surface role, and `outline` stays stronger;
- `focus-ring` is at least 3:1 against surfaces.

Project rules forbid loosening a threshold to make a check pass.

## Target size

The least sizes of what a person presses. minimum is the least height (and, for an icon-only control, width) anything pressable is drawn at; touch and pointer are the least hit areas, which a control reaches past what it draws where it stands alone.

| Token | Value | Preview |
| --- | --- | --- |
| `--tanrei-sys-target-minimum` | 32px |  |
| `--tanrei-sys-target-pointer` | 44px |  |
| `--tanrei-sys-target-spacing` | 8px |  |
| `--tanrei-sys-target-touch` | 48px |  |

Generated from `design/tokens/tanrei.light.tokens.json`, `tokens/sys/measure.tokens.json`

**Visual size is not hit area.** A small Tanrei button is 32 units tall, which suits a dense toolbar, but it still responds across at least 48 units for touch and 44 for a pointer. Components extend their hit area invisibly and keep at least 8 units between neighbouring targets. Every spec declares this guarantee, and every platform tests it.

## Focus

Every interactive component shows the gap-then-ring focus indicator for keyboard and assistive-technology focus, immediately and without animation. Focus order follows reading order. Disabled components leave the focus order.

## Keyboard

Each component spec contains a table of keys and actions, shown on its documentation page under **Accessibility**. Platforms with hardware keyboard support implement the table exactly.

## Text scaling

Interfaces must remain usable with text at **200%**. Containers grow with their text, labels wrap before they truncate, and nothing relies on a fixed height to fit a line of text. Native implementations use each platform’s scalable text mechanism.

## Reduced motion

When the system asks for reduced motion, spatial animation is removed or replaced by a brief fade and nothing loops. See [Motion](https://tanrei.chnotchy.com/foundations/motion/).

## Semantics

A spec names the component’s WAI-ARIA role and how its accessible name is formed. Each platform maps the role to its native equivalent: accessibility traits in SwiftUI, semantics properties in Compose and Flutter, `accessibilityRole` in React Native. On the web, Tanrei prefers native elements inside the shadow root, so that browsers and testing tools see real semantics.

## How it is tested

| Platform | Automated check |
| --- | --- |
| Web | axe-core in Playwright |
| SwiftUI | XCTest accessibility audit |
| Compose | Accessibility Test Framework checks |
| Flutter | `meetsGuideline` matchers |
| React Native | role and label assertions, plus native audits through the gallery app |

> [!NOTE]
> **Note**
>
> Automated checks catch a minority of real problems. They are a floor. Use a screen reader and a keyboard on anything you build with these components.
