Patterns
Accessibility
WCAG 2.1 level AA is the floor for every Tomatico interface. Most of it is handled by using the system correctly — this page covers what the system cannot do for you.
The standard
Every Tomatico digital product meets WCAG 2.1 level AA. That is a floor, not a target, and it follows directly from the brand's human centered value: products "designed for people, made for life" cannot exclude people who use a keyboard, a screen reader, a magnifier or a switch device.
Using the documented components gets you most of the way. The failures that remain are almost always in the parts you write yourself: custom controls, focus management, and words.
What the system already handles
- Contrast. Every semantic token pairing clears AA. See Colour → Contrast.
- Focus. One visible 2px ring on every interactive element, offset by 2px so it reads on any surface, in both themes.
- Touch targets. Controls are 44px tall by default.
- Reduced motion.
prefers-reduced-motionis honoured globally. - Text scaling. Sizes are in
rem, so the browser's font setting is respected. - Direction. Logical properties throughout, so Arabic is not a second-class layout.
- Status without colour. Alerts, badges and invalid fields each carry at least two non-colour signals.
Keyboard
Everything that can be done with a pointer can be done with a keyboard. Test it by unplugging the mouse.
- Tab order follows the visual order. Do not reorder with
tabindexabove 0 — use the DOM order, and let CSS handle the arrangement. - No keyboard traps. Focus can always move on. The one legitimate trap is inside an open modal, and it has to release when the modal closes.
- Focus is always visible. If you find
outline: noneanywhere, it is a bug. - A skip link comes first.
.tmt-skip-linkis hidden until focused. - Escape closes anything that opened over the page, and focus returns to whatever opened it.
| Key | Expected |
|---|---|
| Tab / Shift+Tab | Move between controls, in reading order |
| Enter | Activate a link or a button; submit a form |
| Space | Activate a button; toggle a checkbox or switch |
| Arrow keys | Move within a group: radios, tabs, a menu |
| Escape | Close a dialog, menu or drawer |
Managing focus
This is what most often goes wrong in a single-page application, because nothing about it is visible to a sighted developer testing with a mouse.
- Route change: move focus to the new page's
<h1>(give ittabindex="-1"), and update the document title. Without this, a screen reader user hears nothing when the page changes. - Dialog opens: focus moves inside; the background is inert; closing returns focus to the trigger.
- Content removed: if the focused element disappears, move focus somewhere deliberate first — otherwise it falls to the document body and the person starts again from the top.
- Form fails validation: focus moves to the error summary. See Form validation.
Every control has a name
A control with no accessible name is announced as "button" and is unusable by voice control, which works by speaking the visible label.
<!-- Visible text is the name. Best case. -->
<button class="tmt-btn">Save changes</button>
<!-- Icon only: hidden text keeps the name in the DOM,
so voice control users can still say it. -->
<button class="tmt-btn tmt-btn--icon">
<span class="tmt-visually-hidden">Device settings</span>
<svg aria-hidden="true">…</svg>
</button>
<!-- Fields: a real label, connected by for/id -->
<label class="tmt-label" for="room">Room</label>
<select class="tmt-select" id="room">…</select>
Prefer visible text, then visually hidden text, then
aria-label. The first two also help people who use voice
control or who simply cannot guess what an icon means.
Structure
- One
<h1>per page, then heading levels in order with none skipped. Screen reader users navigate by heading far more than by tabbing. - Landmarks:
<header>,<nav>,<main>,<footer>. One<main>; label each<nav>if there is more than one. - Lists are lists, tables are tables, buttons are buttons. The native
element carries behaviour and semantics that a
<div>with ARIA has to reimplement — and usually reimplements incompletely. - Set
langon the page and on any passage in the other language, so the screen reader switches pronunciation.
Never colour alone
In a monochrome system this is easy to satisfy and easy to forget, because the greys look deliberate either way.
- A status is a word plus an icon or a dot, never a hue on its own.
- An invalid field has a heavier border and a message, not just a red edge.
- A link inside body text is underlined, not merely a different weight.
- Copy never says "the items in red" — it names the state.
The quickest check: view the screen in greyscale. Anything you can no longer distinguish is a failure.
Zoom and reflow
- At 200% zoom, all content and function is still available.
- At 400%, content reflows into a single column with no horizontal scrolling — except for things that genuinely need it, such as a wide data table.
- Text spacing can be increased — line height to 1.5×, paragraph spacing to 2× — without anything being cut off. Fixed-height containers are what break this.
- Nothing depends on hover alone. If information appears on hover, it also appears on focus, and it can be dismissed.
Testing
Automated tools catch perhaps a third of real problems. They are worth running, and they are not sufficient.
- Keyboard pass. Unplug the mouse and complete the main task.
- Screen reader pass. NVDA or Narrator on Windows, VoiceOver on macOS and iOS, TalkBack on Android. Fifteen minutes of listening finds more than an hour of auditing.
- Zoom pass. 200% and 400%.
- Greyscale pass. For colour independence.
- RTL pass. See the RTL checklist.
- Automated pass. axe DevTools, Lighthouse, or WAVE.
Pre-release checklist
- Every image has
alt— descriptive, or empty if decorative. - Every form control has a visible, connected label.
- Every icon-only button has an accessible name.
- Headings are in order, one
<h1>. - Landmarks are present; multiple navs are labelled.
- Focus is visible everywhere, and the tab order matches the visual order.
- Nothing conveys meaning by colour alone.
- Errors are announced and linked to their fields.
- Content reflows at 400% zoom.
langis set on the page and on passages in the other language.- Video has captions; audio has a transcript.
- Nothing auto-plays, flashes more than three times a second, or moves without a way to stop it.