npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@uistate/css

v2.0.1

Published

State-driven CSS: runtime reactive styling, design tokens, typed validation, and relational constraints

Downloads

202

Readme

@uistate/css

State-driven CSS: runtime reactive styling, design tokens, typed validation, and relational constraints. Powered by @uistate/core.

npm version License: MIT

Install

npm install @uistate/css @uistate/core

Style Engine

Compiles EventState dot-paths into real CSS rules. Path segments become selectors, pseudo-classes, and CSS properties automatically.

import { createEventState } from '@uistate/core';
import { createStyleEngine } from '@uistate/css';

const store = createEventState();
const engine = createStyleEngine(store);

// Paths become CSS rules
store.set('css.card.background', '#fff');
store.set('css.card.padding', '1.5rem');
store.set('css.card.hover.boxShadow', '0 4px 6px rgba(0,0,0,0.1)');
// -> .card { background: #fff; padding: 1.5rem; }
// -> .card:hover { box-shadow: 0 4px 6px rgba(0,0,0,0.1); }

// Subtree set — swap an entire theme in one call
store.set('css.card', {
  background: '#1e293b',
  color: '#e2e8f0',
  hover: { background: '#334155' },
});

Design System

Reactive design tokens. Bind tokens to styles: change a token, every bound style updates.

import { createDesignSystem } from '@uistate/css';

const ds = createDesignSystem(store, {
  tokens: {
    color: { primary: '#3b82f6', danger: '#ef4444', surface: '#fff', text: '#1e293b' },
    spacing: { xs: '0.25rem', sm: '0.5rem', md: '1rem', lg: '1.5rem', xl: '2rem' },
    radius: { sm: '0.25rem', md: '0.5rem', lg: '1rem', full: '9999px' },
    font: { sm: '0.875rem', base: '1rem', lg: '1.25rem', xl: '1.5rem' },
  },
});

// Bind style paths to tokens
ds.bind('css.btn.background', 'color.primary');
ds.bind('css.btn.padding', 'spacing.md');
ds.bind('css.btn.borderRadius', 'radius.md');

// Change token -> all bound styles update
ds.setToken('color.primary', '#8b5cf6');

// Bulk theme swap
ds.setTokens({ color: { primary: '#22c55e', surface: '#0f172a', text: '#e2e8f0' } });

// Inspect bindings
ds.getBindings(); // { 'color.primary': ['css.btn.background', ...] }

Typed CSS

Runtime schema validation for styles. Define what properties a component accepts and get meaningful errors on invalid values.

import { createTypedCSS } from '@uistate/css';

const typed = createTypedCSS(store, {
  btn: {
    background: { type: 'color' },
    padding: { type: 'length', min: '0.25rem', max: '3rem' },
    fontSize: { type: 'length', min: '0.75rem', max: '2rem' },
    display: { type: 'enum', values: ['flex', 'inline-flex', 'block', 'none'] },
  },
  card: {
    background: { type: 'color' },
    padding: { type: 'length' },
    boxShadow: { type: 'shadow', maxLayers: 3 },
  },
});

store.set('css.btn.padding', '1rem');     // ✅ valid
store.set('css.btn.padding', '10rem');    // ⚠️ [typed-css] btn.padding: '10rem' exceeds max '3rem'.
store.set('css.btn.display', 'table');    // ⚠️ [typed-css] btn.display: 'table' not allowed.
store.set('css.btn.background', 'banana');// ⚠️ [typed-css] btn.background: not a valid color.

// Add schemas at runtime
typed.defineComponent('badge', { background: { type: 'color' } });

// Inspect schema from state
store.get('schema.btn'); // { background: { type: 'color' }, ... }

Relational CSS

Constraint-based style relationships. Proportional scaling, modular type scales, and WCAG contrast enforcement.

import { createRelationalCSS } from '@uistate/css';

const rel = createRelationalCSS(store);

// Proportional: header padding is always 2x card padding
rel.derive('css.header.padding', { ref: 'css.card.padding', multiply: 2 });

// Modular type scale from a base font size
rel.scale('tokens.font.base', {
  'css.h1.fontSize': 2.0,
  'css.h2.fontSize': 1.5,
  'css.h3.fontSize': 1.25,
  'css.body.fontSize': 1,
  'css.small.fontSize': 0.875,
});
// Change tokens.font.base -> all headings recompute proportionally

// WCAG contrast: auto-pick text color for readability
rel.contrast('css.card.color', {
  against: 'css.card.background',
  light: '#ffffff',
  dark: '#1e293b',
  minRatio: 4.5,  // AA compliance
});
// Change card background to dark -> text automatically switches to white

// Clamp a value
rel.clamp('css.sidebar.width', { ref: 'css.sidebar.width', min: '200px', max: '400px' });

Testing

Two-layer testing architecture:

self-test.js: Zero-dependency self-test (53 assertions). Runs automatically on npm install via postinstall. Tests pure functions: camelToKebab, parsePath, color/length validation, hexToRgb, contrastRatio, parseLength, and formatLength.

node self-test.js

tests/css.test.js: Integration tests via @uistate/event-test (26 tests). Tests the eventState-driven modules through the store: designSystem (token binding, propagation, unbind), typedCSS (schema validation, violations, runtime defineComponent), and relationalCSS (derive, scale, contrast, clamp).

npm test

| Suite | Assertions | Dependencies | |-------|-----------|-------------| | self-test.js | 53 | none (zero-dep) | | tests/css.test.js | 26 | @uistate/event-test, @uistate/core |

Note: cssState and styleEngine require a DOM and are tested in browser. The v2 modules (designSystem, typedCSS, relationalCSS) work entirely through eventState and are fully testable in Node.

Legacy: CSS Custom Properties (v1)

The original CSS state layer: writes state to CSS custom properties and data attributes. Still available for WordPress, static sites, and progressive enhancement.

import { createCssState } from '@uistate/css/cssState';

const ui = createCssState({ theme: 'light' });
ui.init();
ui.setState('theme', 'dark');
// -> :root has --theme: dark and data-theme="dark"

License

MIT — see LICENSE.

Copyright © 2025 Ajdin Imsirovic

Links