<!--
Source: https://www.theui.dev/docs/accessibility
Part of the theui-svelte documentation. Index: https://www.theui.dev/llms.txt
-->

# Accessibility Guide

What **theui-svelte** handles for you, what is left to you, and the keys every component answers to.

Every component ships with its roles, its keyboard behavior and its focus handling already in place, so a modal traps focus and a tab list answers to the arrow keys without any work from you. What the library cannot know is your content: the name of an icon-only button, the text of a label, the colors you pick. That part is yours, and this page marks the line between the two.

## Why Accessibility Matters

Accessible pages let people understand, navigate and use your site whether they see it, hear it, or drive it from the keyboard alone. Much of it is also plain good practice: a page that works without a mouse works on a broken trackpad too, and a field with a real label is easier for everyone to fill in.

## What the Components Handle

These behaviors come with the components. You do not have to add them, and you should not need to work around them.

- **Roles and structure**: `Modal` is a dialog, `Tabs` renders a real tab list, `Dropdown` items carry `menuitem`, `Progress` is a progress bar, `Rating` is a group of radio buttons, and `Breadcrumb`, `Pagination` and `NavLink` mark the current page with `aria-current`.

- **Keyboard**: arrow keys, `Home` and `End` work inside tabs, sliders, menus, the calendar, the time fields, one-time-code boxes and pagination. The table below lists them all.

- **Focus**: a `Modal` moves focus into itself, keeps `Tab` inside while it is open, and hands focus back to whatever opened it. `Escape` closes the modal on top, not all of them. Closed modals and drawers are `inert`, so the keyboard skips what is hidden behind them.

- **Descriptions**: `helperText` is tied to its field with `aria-describedby`, so a screen reader reads the hint along with the label. `Tooltip` and `Popover` describe the element they belong to.

- **Announcements**: a notification announces itself as an alert, the calendar announces the month you move into, and a slider announces slide changes once its autoplay is paused.

- **Tables**: header cells carry `scope`, so a screen reader ties every cell to its column, and a table too wide for its container becomes a named region you can scroll with the keyboard.

- **Motion**: when the system asks for reduced motion, a slider stops playing by itself. Setting `animationSpeed="none"` turns transitions off wherever the prop exists.

## Keyboard Reference

Beyond `Tab` and `Shift + Tab`, which move between the controls on the page, the components answer to these keys.

| Component | Keys |
| --- | --- |
| Tabs | `←` `→` move between tabs, `Home` first, `End` last |
| Slider | Arrow keys move one slide, `Home` first slide, `End` last slide |
| Dropdown, NavDropdown | `↑` `↓` open the menu, `Escape` closes it and returns focus to the trigger, `Enter` follows a link, `Space` presses a button |
| Combobox | Type to filter, `↑` `↓` move, `Home` and `End` jump, `Enter` picks, `Escape` closes, `Backspace` removes the last chip |
| DatePicker | `↓` opens the calendar, arrow keys move by day and week, `Home` and `End` jump to the ends of the week, `PageUp` and `PageDown` change month (with `Shift`, year), `Escape` closes |
| TimePicker | `↑` `↓` change the part you are on, `←` `→` move between hour, minute and AM/PM, `Home` and `End` jump to the lowest and highest value |
| OtpInput | `←` `→` move between boxes, `Backspace` and `Delete` clear, `Home` and `End` jump to the first and last box, and a paste fills the boxes |
| Pagination | `←` `→` move between page links |
| Rating | Arrow keys pick a value, as in any radio group |
| Modal, Drawer, Popup | `Escape` closes the one on top, and `Tab` stays inside an open modal |
| Accordion, Collapse | `Enter` or `Space` on the heading opens and closes it |

## What You Still Have to Do

The library never invents words for your interface. These are the pieces only you can supply.

- **Name icon-only controls.** A button with nothing but an icon has no name to read out. Give it `ariaLabel`. From version 3 the library no longer guesses a name for `Button`, `QabItem` or `NavBrand`, because a guessed name read over the visible text is worse than none.

- **Label every field.** Write the label as the content of the field, and keep `helperText` for the hint. Both are tied to the input for you.

- **Describe images.** A `Slide` with `src` and an `Avatar` with a picture both take `alt`. Leave it empty only when the image says nothing the text does not already say.

- **Mark the current page.** Set `active` on the `NavLink` of the page you are on, and it gets `aria-current="page"`.

- **Name what has no text of its own.** A `Table` takes `ariaLabel` or a `<caption>`, and a `Close` button takes `ariaLabel` to say what it closes. Name a `Container` only when the area is somewhere people would want to jump to, since a named `Container` becomes a landmark.

- **Keep the focus ring.** The components draw a visible ring when a control is focused from the keyboard. If your own CSS removes outlines, put a visible replacement back.

- **Check your colors.** Components take their colors from your theme, so contrast depends on the palette you choose. Aim for 4.5:1 on normal text and 3:1 on large text, icons and borders.

**Name an icon-only button**

```svelte
<Button ariaLabel="Close the menu">
  <Svg><path d="M6 18L18 6M6 6l12 12" /></Svg>
</Button>
```

## Motion and Animation

People who ask their system for reduced motion get less of it: a `Slider` will not play on its own, and its timer bar stays still. The choice is theirs, not a prop, so test it by turning reduced motion on in your operating system. Where you want an element calm for everyone, `animationSpeed="none"` removes its transition.

## Color and Contrast

The components inherit your brand colors, so they are exactly as readable as the palette behind them. Check the shades you picked on the [colors page](https://www.theui.dev/docs/colors) against the background they sit on, in both light and dark mode, and remember that a color alone should never be the only thing carrying a meaning: pair it with text, an icon or a shape.

## Testing Your Pages

Automatic checks catch perhaps a third of what matters. Do the first item on this list before the others.

- **Put the mouse away**: reach every control with `Tab`, use it, and make sure you can always see where you are and can get out of anything you opened.

- **axe DevTools** or **WAVE**: browser extensions that report missing names, bad contrast and broken structure.

- **Lighthouse**: built into Chrome DevTools, useful as a quick pass over a whole page.

- **A screen reader**: VoiceOver on macOS and iOS, NVDA or JAWS on Windows, TalkBack on Android. Listening to one page end to end teaches more than any report.

## Per-Component Notes

Every component page ends with its own **Accessibility** section, covering what that component does, the props that affect it and anything it needs from you. See [Modal](https://www.theui.dev/docs/modal#accessibility), [Tabs](https://www.theui.dev/docs/tabs#accessibility) or [Combobox](https://www.theui.dev/docs/combobox#accessibility) for the shape of it.

## Further Support and Feedback

If something here does not hold up in practice, that is a bug worth reporting. Open an issue on [GitHub](https://github.com/mbparvezme/theui-svelte/issues) with the component and how you were using it, and it will be looked at.

---

Category: Guides
Keywords: accessibility, a11y, keyboard, screen reader, guide, component-library, theui-svelte, svelte
Full documentation set: https://www.theui.dev/llms-full.txt
