---
title: "Accessibility"
description: "What the components guarantee for WCAG 2.2 and what remains the project's responsibility."
requested_language: cs
language: en
translation_notice: "This page isn't translated yet"
url: https://docs.systhema.app/cs/concepts/accessibility
version: unreleased (main)
docs_index: https://docs.systhema.app/cs/llms.txt
---
> This page isn't translated yet. Showing English.


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 own

| Area               | Systhema                                                                   | Your project                                                       |
| ------------------ | -------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| Page structure     | Skip link, `<main>`, `<html lang>` in the templates; real heading elements | A logical heading outline; landmarks in layouts you write yourself |
| Names and labels   | One accessible name on every icon-only control; decorative icons hidden    | Meaningful link text, alt text, labels you pass as props           |
| Keyboard and focus | Menus, accordions and dialogs manage focus, `inert` and `Escape`           | Custom widgets you build                                           |
| Forms              | Descriptions, errors and groups wired with ARIA                            | Clear labels and error messages                                    |
| Motion             | Reveals and parallax respect `prefers-reduced-motion`                      | Your own animations                                                |
| Color and size     | Token-driven, so one change fixes every component                          | Contrast ratios and target sizes in your tokens                    |
| Media              | Titles on embeds, play buttons only where something plays                  | Captions and transcripts for video and audio                       |

## Landmarks and the skip link

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](https://docs.systhema.app/cs/styling/accessibility.md#skip-link).

## Headings

Hero titles and the rich-text headings the editor produces are real `<h1>`–`<h6>` elements ([`Heading`](https://docs.systhema.app/cs/components/heading.md)), not styled `div`s, 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 controls

- 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 that open a new tab

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](https://docs.systhema.app/cs/components/link.md).

## Keyboard and menus

- 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](https://docs.systhema.app/cs/components/header.md).
- Collapsed accordion content is `inert`. See [Accordion](https://docs.systhema.app/cs/components/accordion.md).
- [`MediaWrapper`](https://docs.systhema.app/cs/components/media-wrapper.md) is a focusable button only when it wraps something playable, so a still image is never announced as "Play video".

## Forms

The [form fields](https://docs.systhema.app/cs/components/form-fields.md) 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](https://docs.systhema.app/cs/components/archive-search-filter.md) is a `role="search"` form with labelled dropdowns and named remove buttons.

## Lists and counters

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](https://docs.systhema.app/cs/components/gallery.md).

Content that changes without a page load announces itself: [`PostsList`](https://docs.systhema.app/cs/components/posts-list.md#accessibility) 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 motion

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](https://docs.systhema.app/cs/concepts/motion.md#reduced-motion).

## Color, contrast and target size

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](https://docs.systhema.app/cs/concepts/themes.md).

## Embeds and viewport

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.

## Related

- [Accessibility utilities](https://docs.systhema.app/cs/styling/accessibility.md)
- [Motion](https://docs.systhema.app/cs/concepts/motion.md)
- [Components](https://docs.systhema.app/cs/components.md)
