@arag
A plain-CSS design system for product UI, data-dense dashboards and printed
materials. Native cascade layers, oklch() colour, and layouts that
are safe for long, translated text. A <link> tag is the whole install.
Complete and verified: tokens, reset, base element defaults, twenty-six components and the utility layer. Nothing in the sidebar is a placeholder any more.
Principles
Zero dependencies, zero build
No Sass, no PostCSS, no config file, no class scanner, no JIT engine, no JavaScript required. Nothing to install and nothing to run. The package is four CSS files, and consuming it is one link.
<link rel="stylesheet" href="node_modules/@arag/css/src/index.css">Native CSS only
Everything the system relies on ships in Chrome, Edge, Firefox and Safari:
@layer, custom properties, nesting, color-mix(),
oklch() and light-dark(). What the
preprocessors were for, the platform now does. See
browser support for the version floor.
Tokens all the way down
Every colour, space, radius, shadow, font size, duration and easing curve is a custom property. Component CSS contains no raw values at all: that rule is greppable, and it holds today.
# must return nothing
grep -rnE ':\s*[0-9.]+(px|rem|em|ms)\b' src/base.cssNo priority-raising declarations, ever
Overriding is done with cascade layers, not force. Your application CSS is unlayered, which places it above all six of the system's layers, so plain authoring wins by default. There is not one such declaration in the package, and that is also greppable.
# must return nothing
grep -rn '!important' src/Long-text safe by default
A translated string routinely runs 15–25% longer than its English source. Components size to their content: no fixed button widths, no single-line assumptions in nav, cards or tables. Font stack and line height are tokens. Read the full constraint →
Create a new order
Create a new order from a saved customer basket
Create a new order
Create a new order from a saved customer basket
Those two panels are one page in one theme. Dark mode is
light-dark() switched by color-scheme, which means
[data-theme] works on any subtree, not just the root.
How theming works →
What is in the box
| File | Layer | Lines | Does |
|---|---|---|---|
src/reset.css | reset | 310 | Unstyles browser defaults. Deliberately token-free, so it is correct standalone. |
src/tokens.css | tokens | 1448 | Every literal value in the system. 313 custom properties. |
src/base.css | base | 639 | Element defaults: body, headings, links, tables, form controls, focus. |
src/index.css | none | 56 | Declares the layer order, then imports the files above and below it. This is the entry point. |
src/components/ | components | 9591 | Twenty-six components, one file each: accordion, alert, badge, button, card, carousel, code, collapse, countdown, dialog, drawer, duo, field, icon, masthead, menu, money, progress, rating, scrollspy, skip-link, stat, table, tabs, toast, video. |
src/utilities.css | utilities | 396 | 161 static, hand-picked classes. No generator, no arbitrary values. Every one hands a token through. |
The token surface
313 custom properties, of which 70 are ramp generators, read only by the colour ramps and rarely touched directly, and 243 are the public surface.
| Group | Count | Shape |
|---|---|---|
| Colour | 203 | 5 ramps × 11 steps, 69 semantic roles, 6 state controls, 70 generators, 2 ladder inputs the state shade also reads, 1 scheme flag |
| Typography | 34 | 3 stacks, 5 families, 5 font roles, 8 fluid sizes, 2 underline, 4 leadings, 4 weights, 3 trackings |
| Space & size | 29 | 10 space steps, 15 size ceilings and minimum targets, 4 safe-area insets |
| Radius, border, shadow | 24 | 8 radii, 7 border and focus-ring, 9 shadow |
| Z-index & motion | 23 | 10 stacking levels, 6 durations, 6 easings, 1 shorthand |
Each token page renders its tokens as live swatches in both themes, with the
browser-resolved value beside each name, read at runtime, so the docs cannot drift from
tokens.css.
What this is not
Not a Tailwind or Bootstrap clone. There is no utility generator, no arbitrary-value syntax, no scanner, no config file and no JavaScript framework layer. Utilities will be a static, hand-picked file of roughly 120–150 classes. If it cannot be named, it is not needed.