Quality
Every claim on this page is one of two things: a number counted out of this repository when the page was built, or a gate you can run yourself in one command. Nothing here is a badge somebody drew.
That is a narrower promise than "high quality", and it is deliberate. A design system is adopted by people who will be blamed if it breaks, and what convinces them is not an adjective - it is knowing exactly what is checked, how often, and what is not checked at all. The last section on this page is the second half of that bargain.
What runs, and when
| Command | What it checks | Where it runs |
|---|---|---|
pnpm lint:tokens |
Every foundation token a stylesheet references without a fallback is defined somewhere | every build |
pnpm lint:readmes |
Every component README follows the template the docs are generated from, and documents the events its code dispatches | every build |
pnpm lint:selectors |
Every is selector, and every is in markup, names the element that
component upgrades
|
every build |
pnpm lint |
Biome, across the whole repository | every commit, CI |
pnpm test |
Component behavior, in a real browser rather than a DOM emulation | every commit |
pnpm test:coverage |
The same suite, against the coverage floors below | CI |
pnpm test:e2e |
The built site: the shell, the demos, the roadmap, and the axe accessibility gate | every push, CI |
pnpm build |
The site itself - which runs the three lint gates above before it writes anything | CI |
Nothing in that table is optional. The build refuses to produce a site when a token does not resolve, when a README does not follow the template, or when a stylesheet paints a component onto an element that component cannot be. The commit hook runs the linters and the unit suite; the push hook runs the browser suites; the pipeline runs all of it again on a machine that has never seen this working copy.
What the numbers are
WCAG 2.2 AA21/54
components whose live example is scanned by axe on every push, against the built site
Test suites65
component behavior files, run in a real browser
Statement coverage floor93%
the build fails below it, so the number cannot drift down quietly
65
One or more per component, plus the shared form-control suites
10
The built site: shell, demos, readiness and the roadmap
4
axe against dist/, per component and per shell surface
93/82
Statements and branches, from vitest.config.mjs - functions and lines sit between them
0
Counted across everything that ships, not asserted
0
Across every package manifest in the workspace
451
Plus 1471 declared by components
217
Element and attribute selectors only
Two of those deserve a sentence. Zero CSS classes is counted, not claimed: the figure is the number of class selectors found in everything that ships, and if somebody writes one it stops being zero on the next build. Zero third-party runtime dependencies is counted the same way, across every package manifest in the workspace - the platform is the dependency, and that is a measurement rather than a slogan.
What it costs to load
1.8 kB
Gzipped, which is what the network carries
3.8 kB
Range, the largest single import
58.7 kB
Every one of the 21 finished components at once, which no page needs
216.0 kB
Inter, roman and italic, subset to Latin - a page fetches the roman
| Component | Transfer (gzip) | On disk |
|---|---|---|
| Range | 3.8 kB | 14.1 kB |
| Paginator | 3.4 kB | 11.4 kB |
| Number | 3.2 kB | 12.5 kB |
| Tag | 3.1 kB | 15.9 kB |
| DataTable | 2.8 kB | 10.5 kB |
A component is a file. There is no runtime to load first, no framework to reconcile with, and nothing shared to warm up: a page that uses one component pays for one component. The figures are the built bundles as they are published, and the transfer column is what the network actually carries.
The face costs more than all of them together, and that is worth saying plainly rather than leaving in a waterfall: Inter ships as two unsubset variable files, and on this site they are about two fifths of what a page transfers. Subsetting them is not done.
What this site costs is not what your page costs. Every page here loads every component, because any example may use any of them - 57 JavaScript files, around 900 kB on the wire. A product built on root imports the components it uses and nothing else.
What it must not exceed
| Budget | Ceiling | Today | Gated by |
|---|---|---|---|
| Heaviest component, gzipped | 20 kB | 3.8 kB | pnpm perf:budget |
| Every Ready for Dev component at once | 220 kB | 58.7 kB | pnpm perf:budget |
| Foundation stylesheet, gzipped | 10 kB | 7.8 kB | pnpm perf:budget |
| What one page of this site transfers | 750 kB | measured on every run | pnpm test:e2e |
| Requests one page makes | 90 | measured on every run | pnpm test:e2e |
| Largest Contentful Paint | 2500 ms | measured on every run | pnpm test:e2e |
| Cumulative Layout Shift | 0.1 | measured on every run | pnpm test:e2e |
Budgets are ceilings with headroom, committed in perf.budgets.json and enforced in two
places: pnpm perf:budget weighs the built bundles in every build, and
e2e/performance.spec.js
measures the pages on every run of the browser suite. The two page metrics are the Core Web Vitals
thresholds for "good", measured headless over a loopback interface - they catch a regression,
and they say nothing about a reader on a train. No number here is field data, and none of them is
presented as one.
Accessibility
5
wcag2a, wcag2aa, wcag21a, wcag21aa, wcag22aa - read from the spec itself
21
Each at its first live example, in the built site
5
A dialog scanned closed is a dialog nobody scanned
The gate runs against dist/ - the built artefact that deploys - rather than against a
development server, so what is tested is what ships. Every component flagged Ready for Dev has its live
example scanned for WCAG 2.2 A and AA violations, overlays are re-opened and scanned in their open state,
and the shell's own surfaces are scanned on top of that. Beyond axe, each component's package carries
keyboard and focus tests that run in a real browser.
The formal claim - what conforms, what does not, and where to report what this misses - is the accessibility statement. This section is the measurement behind it.
Where this stops
The honest half. None of the following is checked, and a team adopting this should know it:
- The axe scan reaches one example per component page, the first one, plus the shell surfaces named above. A violation in a component's third example is not caught by this gate.
- Components that are not flagged Ready for Dev are not gated at all - not by axe, not by the release. They are on this site with a warning on every page, which is a different promise from being safe to use.
- Automated accessibility testing finds a fraction of what a person finds. WCAG 2.2 AA as checked by axe is a floor: it catches contrast, names, roles and structure, and it cannot tell you whether a flow makes sense with a screen reader.
- There is no visual regression suite. A change that keeps every test green and moves a component four pixels ships.
- Nothing here measures a single component's render. ADR-004 specified a Container Timing harness for exactly that, was never built, and is superseded by ADR-035: the budgets above are per bundle and per page, so a component that gets slow to paint without getting bigger passes every gate on this site.
- The page metrics are local. LCP and CLS are measured headless, on the machine running the suite, over a loopback interface. They catch a regression against yesterday; they are not a claim about anybody's connection, and there is no field data here.
- The fonts are not subset, and no gate objects: they are outside the bundle ceilings because they are the foundations' own files, and they are the largest thing a page fetches.
- Coverage floors are floors. They stop the number falling; they do not mean the uncovered lines are unimportant.