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
<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 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, Tabs or Combobox 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 with the component and how you were using it, and it will be looked at.