@designsystemsinternational/unocss-preset-design-tokens
v1.0.0
Published
UnoCSS preset for consuming design tokens
Readme
UnoCSS Preset Design Tokens
A custom preset for UnoCSS that consumes design tokens from CSS custom properties and generates atomic utility classes from them. Only the utility classes you actually use end up in the final CSS bundle.
Wait, why not Tailwind?
Tailwind is an extra Layer of Abstraction: Despite Tailwind's move towards CSS variables in v4, it still introduces complexities, such as wrapping variables in @theme instead of using :root. Since I don’t want to go "all-in" on utility styles, but just have them available for sprinkles, overwrites and one-offs, I'm not willing to make that leap. Utilities and my custom CSS should be driven by the same source of truth: my design tokens.
UnoCSS meets this need by allowing to specify exactly what to look for in our CSS without imposing assumptions. It also offers full control over generated utility classes, enabling to maintain a deliberately thin utility layer.
Installation
npm install -D @designsystemsinternational/unocss-preset-design-tokensThe following peer dependencies are required:
npm install -D unocss postcssUsage
Point the preset at your CSS token file(s). The preset reads CSS custom properties from :root and @custom-media rules and maps them to utilities.
// uno.config.js
import { defineConfig } from 'unocss';
import presetDesignTokens from '@designsystemsinternational/unocss-preset-design-tokens';
export default defineConfig({
presets: [
presetDesignTokens({
designTokenFiles: ['./src/tokens.css'],
}),
],
});Token file format
The preset reads standard CSS custom properties from :root and @custom-media for breakpoints:
/* tokens.css */
:root {
/* Colors */
--color-text-primary: #111;
--color-text-secondary: #555;
--color-bg-surface: #fff;
--color-border-default: #e0e0e0;
/* Spacing */
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 2rem;
/* Sizes */
--size-sm: 20rem;
--size-md: 40rem;
--size-lg: 60rem;
}
/* Breakpoints */
@custom-media --md (min-width: 768px);
@custom-media --lg (min-width: 1024px);Available utilities
| Utility | Token prefix | Example |
|---|---|---|
| text-* | --color-text- | text-primary |
| bg-* | --color-bg- | bg-surface |
| border-* | --color-border- | border-default |
| p-*, px-*, py-*, pt-* … | --spacing- | p-md, px-sm |
| m-*, mx-*, my-*, mt-* … | --spacing- | m-lg, mt-xs |
| gap-*, gap-x-*, gap-y-* | --spacing- | gap-md |
| stack-* | --spacing- | stack-md |
| w-*, h-*, min-w-*, max-w-* … | --size- | w-md, max-w-lg |
| leading-* | --leading- | leading-tight |
| tracking-* | --tracking- | tracking-wide |
| weight-* | --font-weight- | weight-bold |
| aspect-* | --aspect- | aspect-video |
| Breakpoints | @custom-media | md:flex |
Design Conventions
These conventions are intentional constraints, not gaps. They reflect how this preset fits into a broader CSS architecture.
Breakpoints are mobile-first only
Only min-width media queries are supported. Breakpoints are defined as @custom-media queries in
your token files and used with a breakpoint: prefix (e.g. md:flex). max-width and range
queries are out of scope — if you need them, write them in component CSS.
Typography is not atomic
There are no font-size utilities. Text styles (size, line-height, tracking, OpenType features)
should be composed into named classes in a fontStyles.css file in your project. The leading-*,
tracking-*, and weight-* utilities exist as overrides, not building blocks.
Positioning belongs in component CSS
There are no position, inset, top, left, z-index, or related utilities. Once you are
positioning something absolutely or managing stacking context, you are deep enough in a component
that those styles belong in a CSS module alongside the rest of the component's layout.
Sizes are token-driven
Width and height utilities (w-*, h-*, min-w-*, etc.) only work with values defined in your
token file as --size-* custom properties. Arbitrary values are intentionally not supported.
The exception is fractional widths (w-1/2, w-3/4, etc.) and w-full / h-full.
How to publish to NPM?
Publishing is handled using an github action. To publish a new version of the package to npm you'll need to create a new release on github.
License
MIT
