Accessibility

What the library does today, read from the component code and the CSS, and what it does not do yet. It is a work in progress, not a claim of WCAG conformance.

Keyboard

EscapeCloses Modal, Drawer, BottomSheet, StepDialog, FullscreenDialog, CommandPalette, Tour and Screensaver. Closes the open list of Select, Dropdown, Menu, Popover and the other popups; focus returns to the trigger.
Tab / Shift+TabInside the dialogs above focus is trapped: it wraps from the last control to the first and back. On open, focus moves to the first control (or the element marked autofocus) and returns to the previous element on close.
Arrow Up / Down, EnterCommandPalette: moves the active option (the input uses aria-activedescendant) and runs it.
Arrow Left / RightCarousel: previous and next slide. Tour: previous and next step, mirrored in RTL.
Enter / SpaceButtons, switches, checkboxes, tabs and options are real button elements, so the browser handles activation.

Roles, labels and focus

Dialogsrole="dialog" with aria-modal and aria-label from the title (Modal, FullscreenDialog, ImageViewer, Screensaver); Tour is a dialog labelled "Tour".
Form controlsSwitch, Checkbox, OptionCard, Rating and RadioGroup carry role and aria-checked; Select and similar pickers expose role="listbox" with role="option" and aria-selected; field errors use role="alert".
TabsTabs and PillTabs use role="tablist", role="tab" and aria-selected.
StatusToast and Snackbar use role="status", Alert uses role="alert", Spinner has an aria-label, Chat messages are a polite live log.
CarouselRegion with aria-roledescription="carousel", slides announced politely when autoplay is off, previous and next buttons labelled.
Icon buttonsIcon-only buttons inside components get an aria-label ("More", "Previous", "Next"). The label text can be overridden through props where the component exposes one.
Focus ringButtons, icon buttons, chips, links, options and inputs show a :focus-visible ring in the brand color.

Motion

  • With prefers-reduced-motion: reduce, transitions and animations inside .zg-root are cut to near zero, and popup, modal and sheet entrance animations are turned off.
  • The data-motion attribute on <html> (on or off) lets users override the system setting. useUiTheme().setMotion('auto|on|off') sets it; auto follows the system and the init script applies it before first paint.
  • Heavy effects (data-fx) can be set to lite; the animated page-background drift runs only at the full level.

Themes and direction

  • Dark and light themes and two palettes are switched with data-theme and data-palette; the Colors page shows every token in both themes.
  • RTL is set with dir="rtl" on <html> (setLocale('ar')). Component styles use logical properties (inset-inline, padding-inline) plus [dir="rtl"] overrides, and keyboard shortcuts that depend on direction, like Tour arrows, are mirrored.

Not covered yet

Arrow-key navigation in widgetsTabs, PillTabs, SegmentedControl, Select lists, Menu and Dropdown items are reached with Tab, not with arrow keys, and do not follow the WAI-ARIA roving tabindex pattern.
TooltipThe text is drawn with CSS from a data attribute, so screen readers do not read it. It appears on hover and keyboard focus only.
ContrastTokens are defined in OKLCH for dark and light and two palettes, but the ratios have not been measured with a tool yet. Some muted text (--zg-text-3) may fall below 4.5:1.
Popup focus handlingSelect, Dropdown and Popover lists close on Escape and outside click but do not move focus into the list or trap it.
Map, drag and dropMap pans with the pointer only. Sortable lists are driven by drag; there is no keyboard way to reorder.
Screen reader testingNo manual testing with NVDA, JAWS or VoiceOver has been recorded. Treat the roles above as intent, not a verified result.
Component stringsBuilt-in labels are English; localization of them is on the roadmap.

The full plan is on the roadmap.

Automated audit (axe)

Report an issue

Found a barrier? Open an issue with the component name, what you tried (keyboard, screen reader and browser), and what happened. Reproductions on the docs site are the fastest to fix.