Foundations
Accessibility
Every component and screen targets WCAG 2.2 AA. This page covers the principles, a checklist per component type, the keyboard map, focus and contrast rules, and screen reader testing.
Target and scope
Section titled “Target and scope”BigBang targets WCAG 2.2 AA on every surface (D-11). The target is the same for components, patterns, screen templates and this documentation site. The conformance report (ACR) states the measured result; it makes no legal-compliance claim.
Accessibility is delivered in two layers:
- Component: Role, name, keyboard, focus, contrast and motion are solved inside the component. Each component’s Accessibility tab describes them.
- Screen: Heading order, page title, error summary, focus flow and content language belong to the team building the screen. A component cannot solve them on its own.
Principles
Section titled “Principles”| Principle | What it means | Example |
|---|---|---|
| Native element first | When the browser has a ready element (<button>, <input>, <a>), use it. ARIA only fills in missing meaning. |
Button renders a native <button>; there is no <div role="button">. |
| The keyboard does everything | Everything done with a mouse can be done with a keyboard, in the same order as on screen. | A dialog closes with Esc and focus returns to the element that opened it. |
| Colour never speaks alone | Status, errors and selection also show as text or shape. | Badge writes the status next to its colour. |
| Motion is optional | With reduced motion, motion is not deleted; it turns into a calm transition. | The loading indicator spins; with reduced motion it stays still. |
| Equal access in both languages | The Turkish and English interface carry the same roles, names and announcements. | Button’s loading text comes from the ui.* catalogue in both languages. |
Checklist by component type
Section titled “Checklist by component type”Before releasing a component or screen, go through the list that fits its type from top to bottom. Each row maps to a WCAG 2.2 success criterion.
Actions (Button, link, icon button)
Section titled “Actions (Button, link, icon button)”| Criterion | Check |
|---|---|
| 2.1.1 Keyboard | Enter and Space start the action; a link opens only with Enter. |
| 2.4.4 Link purpose | Link text read on its own says where it goes; no “click here”. |
| 2.4.7 Focus visible | A 2 px focus ring shows when reached by keyboard. |
| 2.5.3 Label in name | The accessible name starts with the visible label. |
| 2.5.8 Target size | The target is at least 24 × 24 CSS px or has 24 px of space around it. |
| 4.1.2 Name, role, value | An icon-only button has a label. |
Form fields (TextInput and other inputs)
Section titled “Form fields (TextInput and other inputs)”| Criterion | Check |
|---|---|
| 1.3.1 Info and relationships | Every field has a visible <label>; placeholder text never replaces it. |
| 1.3.5 Identify input purpose | Personal data fields carry the right autocomplete value. |
| 3.3.1 Error identification | The error is written as text and tied to the field with aria-describedby. |
| 3.3.2 Labels or instructions | Required fields are marked; format rules are written under the field. |
| 3.3.7 Redundant entry | Information entered earlier in the same process is not asked for again. |
| 1.4.11 Non-text contrast | The field border has at least 3:1 against the surface. |
Status and feedback (Badge, notification, progress)
Section titled “Status and feedback (Badge, notification, progress)”| Criterion | Check |
|---|---|
| 1.4.1 Use of colour | Status is given as text, not by colour alone. |
| 4.1.3 Status messages | A message that appears later is read once in a polite live region; an urgent error is read with alert. |
| 2.2.1 Timing adjustable | A message that closes by itself can be extended, or also stays in a permanent place. |
| 2.2.2 Pause, stop, hide | Motion lasting longer than 5 seconds can be stopped. |
Overlays (dialog, popover, menu, tooltip)
Section titled “Overlays (dialog, popover, menu, tooltip)”| Criterion | Check |
|---|---|
| 2.1.2 No keyboard trap | Esc closes the overlay; focus cycles inside it but there is always a way out. |
| 2.4.3 Focus order | On open, focus moves to the first meaningful element; on close, it returns to the opener. |
| 2.4.11 Focus not obscured (minimum) | Sticky headers and overlays do not cover the focused element. |
| 1.4.13 Content on hover or focus | A tooltip closes with Esc, stays open while hovered and does not vanish on its own. |
| 4.1.2 Name, role, value | A dialog takes its name from its heading (aria-labelledby). |
Navigation (tabs, side menu, pagination)
Section titled “Navigation (tabs, side menu, pagination)”| Criterion | Check |
|---|---|
| 2.4.1 Bypass blocks | A skip link to the main content sits at the top of the page. |
| 2.4.2 Page titled | Every screen has its own <title>. |
| 2.4.8 Location | The selected menu item carries aria-current="page". |
| 3.2.3 Consistent navigation | The menu is in the same order on every screen. |
Data (table, chart, list)
Section titled “Data (table, chart, list)”| Criterion | Check |
|---|---|
| 1.3.1 Info and relationships | Tables use <th> and scope; a sorted column carries aria-sort. |
| 1.1.1 Non-text content | Every chart has a table or text summary of the same data next to it. |
| 1.4.1 Use of colour | Series are told apart by line pattern, marker or direct label as well as colour. |
| 1.4.10 Reflow | A wide table scrolls horizontally inside itself at 320 CSS px; the page does not. |
Images (icon, illustration, logo)
Section titled “Images (icon, illustration, logo)”| Criterion | Check |
|---|---|
| 1.1.1 Non-text content | Decorative icons and illustrations carry aria-hidden="true" and an empty alt; a meaningful icon has a name. |
| 1.4.11 Non-text contrast | A meaningful icon has at least 3:1 against its background. |
| 1.4.5 Images of text | Images contain no text. |
Keyboard map
Section titled “Keyboard map”This table is generated from the component register (apps/docs/src/data/components.ts). When a new component is registered, its rows appear here on their own.
| Component | Key | Behaviour |
|---|---|---|
| Badge | - | Takes no focus; has no keys of its own. |
| Button | Tab | Moves focus; skipped when disabled. |
| Enter | Starts the action or submits the form. | |
| Space | Starts the action. | |
| TextInput | Tab | Focuses the field; skipped when disabled. |
| Shift + Tab | Goes back to the previous field. | |
| Typing keys | Enter the value. | |
| NumberField | Up / Down arrow | Changes the value by one step. |
| Page Up / Page Down | Changes the value by a large step. | |
| Home / End | Jumps to the minimum or maximum. | |
| PasswordInput | Enter / Space | On the eye button, shows or hides the value. |
| SearchInput | Enter | Submits the search. |
| Escape | Clears the value. | |
| OtpInput | Left / Right arrow | Moves between boxes. |
| Backspace | Deletes a character and goes back. | |
| PhoneInput | Enter / Space / Down arrow | Opens the country list. |
| Escape | Closes the list. | |
| Calendar | Arrow keys | Move between days and weeks. |
| Page Up / Page Down | Previous or next month; with Shift, year. | |
| Home / End | First or last day of the week. | |
| Enter / Space | Selects the day. | |
| DatePicker | Digits | Fill the segment and move on. |
| Up / Down arrow | Step the segment up or down. | |
| Left / Right arrow | Move between segments. | |
| Backspace | Clears the segment. | |
| Escape | Closes the calendar. | |
| TimeField | Digits | Fill the segment and move on. |
| Up / Down arrow | Step the segment, wrapping at the ends. | |
| Left / Right arrow | Move between segments. | |
| Backspace | Clears the segment. | |
| DateRangePicker | Digits | Fill a segment; the end date follows the start. |
| Up / Down arrow | Step a segment; move through presets. | |
| Enter / Space | Pick a range end in the calendar. | |
| Escape | Closes the calendar. | |
| Slider | Arrow keys | One step up or down. |
| Page Up / Page Down | A large step; Shift + arrow too. | |
| Home / End | Lowest or highest value. | |
| RadioCard | Tab | Enters the group on the selected card. |
| Arrow keys | Select the previous or next card. | |
| Space | Selects the focused card. | |
| FileDropzone | Tab | To the file input, then the Remove buttons in the list. |
| Enter / Space | Opens the file chooser. | |
| Form | Enter | Submits the form from a field. |
| Tab | Moves between the summary links. | |
| Stepper | Tab | To complete step buttons, then Back and Next. |
| Enter / Space | Returns to a step or runs the button. | |
| SaveBar | Tab | To Discard and Save; skipped while closed. |
| Timeline | Tab | Only to links and buttons inside events. |
| Copy | Enter, Space | Copies the value. |
| MaskedValue | Enter, Space | On the show toggle, reveals or hides the value. |
| MoneyText | - | Takes no focus; has no keys of its own. |
| AmountInput | Digits, comma, point | Type the amount; letters are dropped. |
| Tab | Leaves the field and formats the amount (1,234.50). | |
| IbanInput | Digits | Type the IBAN; spaces are added for you and the caret stays in place. |
| Tab | Leaves the field; an incomplete IBAN gets a message. | |
| DateTimeText | - | Takes no focus; has no keys of its own. |
| CountdownTimer | - | Takes no focus; has no keys of its own. |
| ConsentBlock | Tab | To the text region, the link and the checkbox. |
| Up, Down, Page Up, Page Down | Scroll in the text region. | |
| Space | Checks the box. | |
| NativeSelect | Space, Alt + Down | Open the browser's list. |
| Up, Down, letter keys | Change the option. | |
| CodeBlock | Tab | To the copy button and the scroll region. |
| Left, Right | Scroll long lines in the scroll region. | |
| PreviewCard | Tab | Focus the link; the preview opens after the delay. |
| Enter | Follow the link. | |
| Escape | Close the preview. | |
| MonthPicker | Arrow keys | Move between cells. |
| Page Up, Page Down | Previous or next page. | |
| Enter, Space | Choose the cell. | |
| Escape | Close the grid. | |
| YearPicker | Arrow keys | Move between cells. |
| Page Up, Page Down | Previous or next page. | |
| Enter, Space | Choose the cell. | |
| Escape | Close the grid. | |
| Autocomplete | Up, Down | Highlight suggestions. |
| Enter | Write the highlighted suggestion into the field. | |
| Escape | Close the list. | |
| DateTimePicker | Tab | To the date segments, the calendar button and the time segments. |
| Up, Down, digits | Change the segment value. | |
| ContextMenu | Up, Down | Move between items. |
| Enter, Space | Run the item. | |
| Right, Left | Open or close a submenu. | |
| Escape | Close the menu. | |
| Popconfirm | Tab | Between the cancel and confirm buttons. |
| Enter, Space | Press the focused button. | |
| Escape | Cancel and close. | |
| InlineEdit | Enter | Open the field from the edit button; save in the field. |
| Escape | Drop the change and close. | |
| Anchor | Tab | Move between the links. |
| Enter | Go to the section. |
Keys every component follows:
| Key | Behaviour |
|---|---|
| Tab / Shift + Tab | Moves to the next or previous focusable element. |
| Esc | Closes the open overlay and returns focus to its opener. |
| Arrow keys | Move inside composite widgets (tabs, menu, radio group). A composite widget is a single stop in the Tab order. |
| Home / End | Go to the first or last item in a composite widget. |
Do not use a positive tabindex. Focus order comes from DOM order.
- The focus ring is drawn in
color-focus-ring, 2 px thick (border-width-focus) and 2 px outside the element. - The ring shows only when reached by keyboard (
:focus-visible). It does not show on mouse click; in fields the text caret already shows the position. - The ring is drawn as an
outline, not a border, so it also shows in Windows high contrast mode. - Sticky headers, bottom bars and notifications never cover the focused element (2.4.11). Give scroll containers
scroll-padding. - When an overlay closes, a row is deleted or a page opens, focus moves to a deliberate place: the opener, the next row or the page heading.
focus:outline-noneColour contrast
Section titled “Colour contrast”The ratios below are computed from the selected brand’s built tokens for light and dark mode. Switch the brand and the table changes with it. The build gate is the packages/tokens/test/contrast.test.mjs test; if a pair falls below the threshold, the brand does not build (BRAND-07).
Text: at least 4.5:1
Section titled “Text: at least 4.5:1”| Foreground / background | Sample | Light mode | Dark mode |
|---|---|---|---|
text-defaultsurface-default | Aa | 16.73:1 Pass16.73:1 Pass16.73:1 Pass | 15.97:1 Pass15.97:1 Pass15.97:1 Pass |
text-subtlesurface-default | Aa | 9.67:1 Pass9.67:1 Pass9.67:1 Pass | 11.24:1 Pass11.24:1 Pass11.24:1 Pass |
text-subtlestsurface-raised | Aa | 7.81:1 Pass7.81:1 Pass7.81:1 Pass | 5.85:1 Pass5.85:1 Pass5.85:1 Pass |
text-placeholdersurface-raised | Aa | 4.74:1 Pass4.74:1 Pass4.74:1 Pass | 5.85:1 Pass5.85:1 Pass5.85:1 Pass |
text-linksurface-default | Aa | 7.57:1 Pass16.73:1 Pass16.73:1 Pass | 7.70:1 Pass15.97:1 Pass15.97:1 Pass |
action-on-primary-defaultaction-primary-default | Aa | 5.92:1 Pass17.17:1 Pass17.17:1 Pass | 9.15:1 Pass14.23:1 Pass14.23:1 Pass |
action-on-danger-defaultaction-danger-default | Aa | 6.45:1 Pass6.45:1 Pass6.45:1 Pass | 9.73:1 Pass9.73:1 Pass9.73:1 Pass |
status-success-foregroundstatus-success-background | Aa | 7.09:1 Pass7.09:1 Pass7.09:1 Pass | 10.48:1 Pass10.48:1 Pass10.48:1 Pass |
status-warning-foregroundstatus-warning-background | Aa | 7.41:1 Pass7.41:1 Pass7.41:1 Pass | 10.48:1 Pass10.48:1 Pass10.48:1 Pass |
status-danger-foregroundstatus-danger-background | Aa | 7.68:1 Pass7.68:1 Pass7.68:1 Pass | 10.54:1 Pass10.54:1 Pass10.54:1 Pass |
status-info-foregroundstatus-info-background | Aa | 7.28:1 Pass7.28:1 Pass7.28:1 Pass | 10.44:1 Pass10.44:1 Pass10.44:1 Pass |
data-positivesurface-raised | Aa | 5.68:1 Pass5.68:1 Pass5.68:1 Pass | 10.21:1 Pass10.21:1 Pass10.21:1 Pass |
data-negativesurface-raised | Aa | 6.45:1 Pass6.45:1 Pass6.45:1 Pass | 9.60:1 Pass9.60:1 Pass9.60:1 Pass |
Minimum: 4.5:1
Borders, icons and focus: at least 3:1
Section titled “Borders, icons and focus: at least 3:1”| Foreground / background | Sample | Light mode | Dark mode |
|---|---|---|---|
border-inputsurface-raised | Aa | 3.36:1 Pass3.36:1 Pass3.36:1 Pass | 3.19:1 Pass3.19:1 Pass3.19:1 Pass |
focus-ringsurface-raised | Aa | 5.92:1 Pass4.74:1 Pass4.74:1 Pass | 6.99:1 Pass4.50:1 Pass4.50:1 Pass |
border-focussurface-default | Aa | 5.52:1 Pass16.73:1 Pass16.73:1 Pass | 7.70:1 Pass13.23:1 Pass13.23:1 Pass |
icon-defaultsurface-default | Aa | 14.12:1 Pass14.12:1 Pass14.12:1 Pass | 15.29:1 Pass15.29:1 Pass15.29:1 Pass |
icon-subtlesurface-raised | Aa | 4.74:1 Pass4.74:1 Pass4.74:1 Pass | 5.85:1 Pass5.85:1 Pass5.85:1 Pass |
icon-dangersurface-raised | Aa | 5.04:1 Pass5.04:1 Pass5.04:1 Pass | 7.43:1 Pass7.43:1 Pass7.43:1 Pass |
icon-successsurface-raised | Aa | 4.39:1 Pass4.39:1 Pass4.39:1 Pass | 8.19:1 Pass8.19:1 Pass8.19:1 Pass |
action-primary-defaultsurface-default | Aa | 5.52:1 Pass16.73:1 Pass16.73:1 Pass | 7.70:1 Pass13.23:1 Pass13.23:1 Pass |
Minimum: 3:1
Ratios are not rounded; 4.49:1 fails. Logos are exempt. Decorative lines (border-default, border-subtle) do not identify a control, so they do not need 3:1.
Target size
Section titled “Target size”Every pointer target is at least 24 × 24 CSS px or has 24 px of empty space around it (2.5.8). Primary controls are 40 px high on desktop and 48 px at the 390 px breakpoint. Links inside running text are exempt.
Zoom and reflow
Section titled “Zoom and reflow”- At 200 % zoom, the screen loses no content or function (1.4.4).
- At 320 CSS px width (400 % at 1280 px) the page does not scroll horizontally; only two-dimensional content such as tables and charts scrolls inside itself (1.4.10).
- Text is not cut off when line height goes to 1.5, paragraph spacing to 2, letter spacing to 0.12 and word spacing to 0.16 times the font size (1.4.12). Do not give text boxes a fixed height.
- Amounts, IBANs, reference numbers, dates and error text are never truncated; when they do not fit, they wrap (I18N-16).
Reduced motion
Section titled “Reduced motion”When motion is reduced in the operating system or data-motion="reduce" is set in the product, duration tokens drop to 0-1 ms. Motion is not deleted; a short opacity transition (at most 110 ms) takes its place. Success marks appear still. Details are on the Motion page.
- Motion longer than 5 seconds can be stopped; only the loading indicator loops without end (2.2.2).
- Nothing flashes more than three times per second (2.3.1).
- Parallax, moving backgrounds and autoplaying video are not used in product screens.
Screen reader testing
Section titled “Screen reader testing”Automated tests find only part of the problems. Before release, every component is tested by hand with the pairings below; the date goes into the a11yTested field in components.ts.
| Screen reader | Browser | Platform | Required |
|---|---|---|---|
| NVDA | Firefox and Chrome | Windows | Yes |
| VoiceOver | Safari | macOS | Yes |
| VoiceOver | Safari | iOS (390 px) | Yes |
| TalkBack | Chrome | Android | For Android apps |
| JAWS | Chrome | Windows | When the customer asks |
Test steps
Section titled “Test steps”- Go through the page from start to end with the keyboard only. Note that every focus stop is visible and the order makes sense.
- Turn on the screen reader and reach the component with Tab. Write down the name, role and state read out (selected, expanded, disabled, invalid).
- Reach the same component in reading mode (browse mode in NVDA, VO + arrow keys in VoiceOver). The text read out must be the same.
- Trigger every state of the component: loading, error, success, open and closed. Check that each change is announced once and with the right priority.
- Switch the interface language to English and repeat steps 2-4. The language read out must match the page’s
lang. - Open each finding as an issue in the repository: date, screen reader and version, browser and version, finding.
How to write the output
Section titled “How to write the output”Write the expected output in quotes, in the order the screen reader reads it. Example: “Save, button”. Screen readers may use a different order; as long as name and role are the same, a difference in order is not a defect.
Automated tests
Section titled “Automated tests”packages/uitests check each component in jsdom for keyboard, focus and announcements.- Storybook stories are scanned with axe; the target is
violations = 0. axe “incomplete” results are closed by hand. - On screen templates, Playwright and axe run for every route and state (A11Y-01..20).
- If an accessibility blocker is found in sign-in, one-time password, confirmation or consent flows, the release does not ship.
Guidelines
Section titled “Guidelines”Do not replace the label with a placeholder
Section titled “Do not replace the label with a placeholder”<TextInput label=“Email address” /><input placeholder=“Email address” />Name controls that carry only an icon
Section titled “Name controls that carry only an icon”<IconButton icon=“x” label=“Close” /><button><XIcon /></button>