Base library: why Lit?
- Lit ✅
- Stencil
- Plain vanilla
~5 KB, declarative reactivity, maintained by Google, no proprietary compiler — it’s a thin layer over the platform standard. Easy to hire for and learn. If Lit disappeared tomorrow, the components would still be valid custom elements.
Design tokens: Style Dictionary as the source of truth
Tokens are authored once as plain JSON (src/colors.json, src/size.json, src/font.json) and compiled by Style Dictionary into CSS, SCSS, JS, TS, and JSON — one source feeding every consumption style (CSS custom properties, SCSS maps, typed JS/TS constants, or a flat JSON for APIs/config).
This is a stronger starting point than a single hand-written
tokens.css: adding a new output platform (e.g. a future React Native or mobile target) means adding a new Style Dictionary platform entry in config.json, not hand-maintaining a parallel file.CSS separated from behavior, per component
Each component’s style lives in its ownstyle.css, imported with the ?inline Vite suffix and applied via Lit’s unsafeCSS() — instead of a css tagged-template string embedded inside the component’s .ts file.
Keeping style in a real
.css file means editor tooling (syntax highlighting, linting, autocomplete) works normally, and a change to visual design never touches the behavior file’s diff.Unit tests: real browser instead of a simulated DOM
Vitest runs unit tests in real Chromium via Playwright, notjsdom. Web components depend on platform APIs (Shadow DOM, custom elements) that DOM simulators implement incompletely — testing in a real browser removes a whole class of false positives/negatives.
Validation: an exported utility, not a Lit dependency
@root-axis/design-system exports Zod schemas (nameSchema, emailSchema, passwordSchema, createPasswordSchema) and a validationErrorMessage(schema, value) helper — but no component imports Zod.
The validation rule lives in one place so it isn’t duplicated (and doesn’t drift) across React, Next, Vue, Solid, and Svelte consumers, but the design system itself stays framework- and validation-library-agnostic. A consuming app calls
schema.safeParse(value) (or validationErrorMessage) and passes the resulting message into whichever error-display prop a future input component exposes.Versioning and distribution
- Each repository (
design-system,design-tokens,docs,examples) is versioned and published independently — there’s no unified monorepo today, sodesign-systemanddesign-tokenscan be on different release cadences. - Published to the public npm registry under the
@root-axisscope — these are open-source packages, not internal-only.