Quality
What we promise about every component, and how much of it we can show. The numbers below are measured from the source at build time, not written by hand. See each item on Verified.
Measured from the code
- Components measured
- 139
- plus 36 charts
- Safe to render on the server
- 139
- 100%
- Animated and reduce motion
- 40 / 47
- 85%
- With accessibility notes or ARIA
- 132
- 95%
- With a docs page
- 136
- 98%
- With a live demo
- 134
- 96%
- With their own unit tests
- 84
- 2234 test files in the repo
The bar
WAI-ARIA and keyboard
Interactive widgets follow the WAI-ARIA Authoring Practices, most of them on Radix primitives. Everything is reachable with Tab and operable with Enter, Space, arrows and Escape, with a visible focus ring.
Reduced motion
Animated components check prefers-reduced-motion and stop or shorten their motion. Decorative effects are hidden from assistive technology.
Server rendering
Components render on the server first. Browser APIs are touched only inside effects and handlers, so nothing crashes or mismatches during hydration.
Light and dark
Colours come from the shadcn CSS variables, so every component follows your theme and dark mode without extra classes.
React 19 and Tailwind 4
Built and tested on React 19.3.0, Next.js 16 and Tailwind CSS 4, in TypeScript strict mode.
Tested and linted
Vitest and Testing Library for behaviour, Playwright with axe for accessibility in a real browser, and jsx-a11y lint rules on every commit.
The rules we build to
Your coding agent can read the same list through the get_quality_rules MCP tool, so its first draft follows them too.
01
Every control has an accessible name
Screen readers announce buttons, inputs and links by name. An icon-only button without one is silent. Give icon-only buttons an aria-label or visually hidden text, and pair every input with a <label> or aria-labelledby.
02
Use the element that already does the job
Native buttons, links and form controls come with focus, keyboard activation and roles for free. Use <button> for actions and <a href> for navigation. Do not put onClick on a <div>.
03
Everything works from the keyboard
People who cannot use a pointer navigate with Tab, arrows, Enter, Space and Escape. Follow the WAI-ARIA Authoring Practices pattern for composite widgets (menus, tabs, listboxes); the Radix primitives in components/ui already do.
04
Focus is always visible
Keyboard users need to see where they are. Never remove outlines without a replacement. Use the shared focus-visible:ring-ring style.
05
Respect reduced motion
Large or endless motion can make people with vestibular disorders unwell. Check prefers-reduced-motion (useReducedMotion from motion, or Tailwind's motion-reduce: and motion-safe: variants) and stop or shorten animation.
06
Colours come from theme tokens
Hard-coded colours ignore the user's theme and usually break in dark mode. Use bg-background, text-foreground, bg-primary, border-border, var(--chart-1) and the other shadcn CSS variables.
07
Text contrast of 4.5:1 or more
Low contrast text is hard to read for many people, and in bright light for everyone. Use muted-foreground for secondary text on background or card, never a lighter custom grey.
08
Works in light and dark
Many people browse in dark mode, and the theme switch should not break anything. Rely on tokens rather than dark: overrides; check both modes before shipping.
09
Safe to render on the server
React 19 and the Next.js App Router render on the server first. Browser globals at module scope crash that render. Touch window, document and localStorage only inside effects or event handlers, or behind a typeof window check.
10
No sideways scrolling on a phone
A layout wider than 360 px hides content on small screens. Use min-w-0 on flex and grid children, wrap long strings (break-words), and let tables scroll inside their own container.
11
Loading, empty and error states
Real data is slow, missing or broken some of the time. Show a Skeleton while loading, an Empty state with a next step when there is nothing, and an error with a retry.
12
Images have alt text
Screen readers read the alt text; decorative images should be skipped. Describe meaningful images in alt, and use alt="" with aria-hidden for decoration.
What these numbers do not tell you
- The server-rendering and reduced-motion checks read the source. They find browser globals at module scope and missing motion guards, not every runtime problem.
- Automated accessibility checks find only part of the problems. A pass is not the same as a full screen reader review.
- Many components have no test file of their own yet; their behaviour is covered by shared primitive tests and the end-to-end axe gate on docs pages. We publish the count anyway.
- The numbers describe our copy. Once you edit a component, they describe ours, not yours.