Appearance
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-onlyon a focusable element: keyboard users would land on something invisible. - Don't hide text with
display: noneorvisibility: hidden: both remove it for screen readers too.