Skip to content

Accessibility Principles ​

Every qs-* component targets WCAG 2.2 AA in both themes. These principles apply to the components and to the pages you build with them.

Native elements first ​

Components render the native element for the job (<a>, <button>, <dialog>, <h1>–<h6>) and add ARIA only for what the element can't express, such as aria-current="page" on a link.

Never colour alone ​

Meaning is carried by more than colour: links are always underlined, the current page is heavier and loses its underline, errors pair colour with text.

Contrast ​

  • Text: at least 4.5:1 against its background.
  • Borders, icons and focus rings: at least 3:1.

Every text/background token pair is checked in both themes before it ships.

Focus ​

Keyboard focus shows a ring from the --focus-outline-* tokens on :focus-visible, so keyboard users see it and mouse clicks don't trigger it. Never remove it without a visible replacement.

Motion ​

Hover effects run only on devices that can hover. Under prefers-reduced-motion: reduce, components keep colour and fades and drop movement.

Decorative icons ​

An icon next to text is decorative: qs-icon is aria-hidden="true" by default. The meaning goes into the control itself, never into the icon alone. An icon-only control gets its name from label.

Utilities ​

sr-only ​

sr-only hides text on screen but keeps it in the accessibility tree. Use it to add context that sighted users get from the layout or an icon.

html
<a href="https://www.w3.org/WAI/" target="_blank" rel="noopener noreferrer">
  WAI
  <qs-icon name="external-link"></qs-icon>
  <span class="sr-only"> (opens in a new tab)</span>
</a>

Screen readers announce "WAI (opens in a new tab)"; the icon stays decorative. qs-link external does this for you.

The other way to give the same information is an aria-label on the link. It replaces the link's content as its accessible name, so it must start with the visible text (WCAG 2.5.3, label in name). On qs-link, set label:

html
<qs-link href="https://www.w3.org/WAI/" external label="Read more about WAI">Read more</qs-link>
<!-- name: "Read more about WAI (opens in a new tab)" -->

Prefer sr-only text when the visible text is enough on its own; use label when it needs more context ("Read more", "Download").

  • Don't put sr-only on a focusable element: keyboard users would land on something invisible.
  • Don't hide text with display: none or visibility: hidden: both remove it for screen readers too.