A token-based, framework-agnostic design system for accessible, modern web UI.
Live Storybook · Components · Design Tokens · Accessibility · Contributing
Construct is a single source of design truth that ships portable CSS, validated design tokens, and opt-in headless behaviors — without framework lock-in. Style values live once as JSON tokens and compile to CSS custom properties, JSON, and typed TypeScript exports. Components use ct- classes and ARIA/data state, so they work anywhere that renders DOM.
- 🎯 Three token layers — primitive, semantic, and component contracts with schema and contrast validation
- 🧩 Framework-agnostic — 49 standalone component style entries and a full CSS bundle
- ♿ Accessibility first — WCAG 2.2 AA targets, tested ARIA/keyboard controllers, focus and forced-colors contracts
- ⚙️ Optional behavior — nine typed, dependency-free ESM controllers; importing CSS never starts JavaScript
- 🎨 Three themes —
light,dark,high-contrast, with system-preference fallback - 📐 The "datum" grammar — a signature orange reference line for focus / active / current state
- 🛠️ Typed tokens — autocomplete-friendly TypeScript exports
- 📖 Interactive docs — every component documented & a11y-tested in Storybook
npm install @neuravision/constructUsing Angular? Reach for the official wrapper @neuravision/ng-construct — typed, signal-based components built on top of these styles.
Import the foundation styles and the component bundle once (e.g. in your global stylesheet):
@import "@neuravision/construct/foundations.css";
@import "@neuravision/construct/components/components.css";Then use the classes in your markup:
<button class="ct-button" type="button">Primary</button>
<button class="ct-button ct-button--secondary" type="button">Secondary</button>
<div class="ct-field">
<label class="ct-field__label" for="email">Email</label>
<input class="ct-input" id="email" type="email" placeholder="name@company.com" />
</div>Or build custom UI directly on the tokens:
.custom-card {
background: var(--color-bg-surface);
color: var(--color-text-primary);
padding: var(--space-4);
border-radius: var(--radius-control);
}💡 Need a smaller bundle? Import a generated standalone style entry such as
@import "@neuravision/construct/components/button.css";. Related public patterns can share an entry: Radio is included incheckbox.css, and Metric is included indatum.css.
Composite widgets can use the optional behavior entry instead of reimplementing keyboard and focus state machines:
import { createModalController } from '@neuravision/construct/behaviors';Foundations make no network request. Import @neuravision/construct/fonts.css before foundations only when the product explicitly accepts the hosted-font privacy and CSP tradeoff; self-hosting is documented in docs/fonts.md.
Set data-theme on the root element (or any container) to switch modes:
<html data-theme="dark"> … </html>| Value | Description |
|---|---|
light |
Default theme |
dark |
Dark theme |
high-contrast |
Maximum-contrast theme |
With no data-theme set, Construct respects system preferences automatically:
prefers-color-scheme: dark → dark, prefers-contrast: more → high-contrast.
Validated product themes can extend a built-in theme without copying generated CSS:
npx construct-theme --theme ./brand.theme.json --out-dir ./src/generated/constructLoad the generated token stylesheet after all Construct style entries, because foundations and component entries include the built-in token sheet themselves:
@import '@neuravision/construct/foundations.css';
@import '@neuravision/construct/components/components.css';
@import './generated/construct/tokens.css';Application-specific overrides may follow it. Keeping the generated theme last among Construct imports ensures its root and scoped values win deterministically.
The package ships validated preset themes in themes/ — brand skins that
compile through the same CLI instead of being baked into tokens.css:
npx construct-theme --theme node_modules/@neuravision/construct/themes/walnut.theme.json --out-dir ./src/generated/construct| Preset | Character |
|---|---|
walnut |
Warm ivory light theme with walnut-brown brand color; AAA body-text contrast enforced by built-in gates |
49 standalone component style entries, documented and accessibility-tested in Storybook.
| Category | Components |
|---|---|
| Actions | Button · Toggle Group · Toolbar |
| Forms & Inputs | Field · Input · Textarea · Select · Select Menu · Checkbox · Radio · Switch · Slider · Combobox · Chip · File Upload · Datepicker |
| Data Display | Table · Data Table · List · Tree · Avatar · Badge · Icon · Tooltip · Chart · Metric · Meter |
| Feedback | Alert · Banner · Toast · Spinner · Skeleton · Progress Bar · Status · Empty State |
| Navigation | Navbar · Breadcrumbs · Tabs · Pagination · Sidebar · Skip Link |
| Overlays | Modal · Drawer · Popover · Dropdown |
| Layout | Card · Divider · Accordion · App Shell (V1 compatibility + V2 recommended) |
→ Explore every component in the live Storybook
Construct uses a three-layer token system: raw primitives, theme-aware semantic aliases, and stable component decisions.
The build pipeline (npm run build) compiles tokens/*.json into:
tokens.css— CSS custom properties (--color-brand-accent)tokens.json— resolved values for toolingtokens.ts/tokens.js— typed exports
⚠️ Never hand-edit generated files (tokens/tokens.*). Edit the source JSON and runnpm run build.
Accessibility is a first-class requirement, not an afterthought:
- ✅ Semantic HTML and explicit ARIA/data-state markup contracts
- ✅ Optional tested keyboard behavior (roving tabindex, focus traps, arrows, typeahead, focus return)
- ✅ Visible focus indicators (the orange "datum")
- ✅ Automated WCAG contrast pairs across built-in and custom themes
- ✅ Screen-reader semantics and documented live-region patterns for dynamic content
- ✅ Respects
prefers-reduced-motion
The Storybook a11y addon is configured to fail the build on violations. See docs/guidelines.md for the detailed patterns.
| Distribution | Plain CSS + design tokens + optional dependency-free ESM behaviors |
| Docs & tests | Storybook 10 · Vitest 4 · Playwright (story-driven) |
| a11y testing | @storybook/addon-a11y (fails on violations) |
| Token build | Custom pipeline (scripts/build-tokens.mjs) |
npm install # install dependencies
npm run storybook # dev server → http://localhost:6006
npm run audit # reject high/critical dependency advisories
npm run build # build token and standalone CSS outputs
npm run check # verify generated, schema, contrast, CSS, export & version contracts
npm test # run behavior, Storybook, touch & forced-colors browser tests| Framework | Status |
|---|---|
| Vanilla HTML / CSS | ✅ Available — use the ct- classes directly |
| Angular | ✅ Available — @neuravision/ng-construct |
| React | ✅ CSS + headless controllers; lifecycle example |
| Svelte | ✅ CSS + headless controllers |
- Design Guidelines — do's, don'ts & accessibility patterns
- Component Usage — HTML patterns and examples
- Token Reference — token structure & naming
- Architecture — package layers and ownership boundaries
- Headless Behaviors — typed controllers and lifecycle
- Fonts — network-free defaults, hosted opt-in, self-hosting
- Governance — Definition of Done and release gates
- Changelog — release history
Contributions are welcome! Please read the Contributing Guide and our Code of Conduct before opening a PR. Found a security issue? See SECURITY.md.
MIT © Construct contributors
