Docs

This page isn't translated yet

next

Accessibility

What the components guarantee for WCAG 2.2 and what remains the project's responsibility.

On this page

Systhema holds the markup of its components and templates to WCAG 2.2: semantics, ARIA, keyboard use, forms, media and motion. Some criteria depend on decisions only your project makes, such as color contrast, target sizes and the words you write. This page lists what the components handle and what stays with you.

What Systhema handles and what you ownLink to this section

AreaSysthemaYour project
Page structureSkip link, <main>, <html lang> in the templates; real heading elementsA logical heading outline; landmarks in layouts you write yourself
Names and labelsOne accessible name on every icon-only control; decorative icons hiddenMeaningful link text, alt text, labels you pass as props
Keyboard and focusMenus, accordions and dialogs manage focus, inert and EscapeCustom widgets you build
FormsDescriptions, errors and groups wired with ARIAClear labels and error messages
MotionReveals and parallax respect prefers-reduced-motionYour own animations
Color and sizeToken-driven, so one change fixes every componentContrast ratios and target sizes in your tokens
MediaTitles on embeds, play buttons only where something playsCaptions and transcripts for video and audio

The Payload page templates render <main id="main-content">, and RootLayout renders a skip link to it as the first element in <body> and sets <html lang> to the active locale. In your own layouts, add the skip-link class to a link to #main-content and give the page's main content that id; the class ships in the base layer, so it works whatever Tailwind scans. See Accessibility utilities.

HeadingsLink to this section

Hero titles and the rich-text headings the editor produces are real <h1>–<h6> elements (Heading), not styled divs, so the outline depends only on the levels you and your editors pick. Post cards use <h3> and the highlight card <h2> by default.

Icons and icon-only controlsLink to this section

  • Decorative icons (ButtonIcon, ChipIcon, the accordion icon, the share glyphs) render with aria-hidden="true", and inline SVGs also get focusable="false". Pass aria-hidden={false} and a label for an icon that carries meaning.
  • Icon-only controls (carousel and gallery navigation, menu toggles, social and share links) have exactly one accessible name: visually hidden text (sr-only!) or an aria-label, never both, because an aria-label replaces the inner text.
  • The Payload Button and Chip blocks can hide their title visually and keep it for screen readers, and a linked Icon block always has a name (its label, or one derived from the link's domain).

What you pass in is yours to get right: alt text, link text that names the destination, and translated labels (labels props, the frontend message catalogs).

Links with target="_blank" get rel="noopener noreferrer" and an "(opens in new tab)" cue: visually hidden text on a text link, or part of the aria-label on an icon-only link. See Link.

Keyboard and menusLink to this section

  • The header's mobile menu keeps aria-expanded in sync, makes the closed menu and, while it is open, the rest of the page inert, moves focus into the menu and back, and closes on Escape. The current page's link has aria-current="page". See Header.
  • Collapsed accordion content is inert. See Accordion.
  • MediaWrapper is a focusable button only when it wraps something playable, so a still image is never announced as "Play video".

FormsLink to this section

The form fields connect each control to its description and error with aria-describedby, set aria-invalid on a failed field, give radio and checkbox groups a role and a label (aria-labelledby), and announce errors with role="alert". Email and phone fields set autoComplete to email and tel. The archive filter is a role="search" form with labelled dropdowns and named remove buttons.

Lists and countersLink to this section

Footer link collections are real lists (<ul>), with display: contents so the layout is unchanged. The gallery's slide counter announces "current / total" images in a status region; see Gallery.

Content that changes without a page load announces itself: PostsList sets aria-busy while loading and reports loading and the running count in a status region, and its empty state is a live region.

Reduced motionLink to this section

For visitors who prefer reduced motion, every reveal shows its end state at once (never opacity: 0, with or without JavaScript), and the parallax engine writes no transform. Both follow a change of the preference without a reload. Animations you write yourself need their own prefers-reduced-motion rule. See Motion.

Color, contrast and target sizeLink to this section

Every color and size comes from your tokens, so contrast and target size are decided in Figma and in customTokens, not in the components. Check text and interactive colors in every theme against WCAG's contrast ratios (4.5:1 for body text, 3:1 for large text and UI boundaries), including muted text such as foundations.text-muted, and keep touch targets at least 24 by 24 CSS pixels. Fixing a token fixes every component that uses it. See Themes and backgrounds.

Embeds and viewportLink to this section

Google Maps embeds render with a title. The scaffolded root layouts never set maximumScale or userScalable in the viewport, so visitors can pinch-zoom; keep it that way in layouts you write. Video blocks have no caption track or caption upload yet, so provide captions or a transcript another way when a video has speech.