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

chaincss

v2.15.19

Published

The design-system compiler with compile-time accessibility and multi-target emission.

Readme

ChainCSS

npm version npm downloads license

📖 Full Documentation →

A zero-runtime, type-safe style compiler platform for modern web applications.

ChainCSS transforms fluent TypeScript style definitions into optimized CSS through a real compiler pipeline. Instead of generating styles at runtime, it analyzes, validates, optimizes, and emits deterministic outputs during the build, resulting in fast applications, framework-independent styling, and predictable performance.

npm install chaincss

Quick Example

Vite

npm create vite@latest my-app -- --template react-ts
cd my-app && npm install chaincss
// vite.config.ts
import chaincss from 'chaincss/vite'
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [chaincss({ atomic: true }), react()],
})
// button.chain.ts
import { chain } from 'chaincss';

export const button = chain()
  .box({ p: '12px 24px', br: 8 })
  .background({ color: '#6366f1' })
  .typography({ color: '#ffffff', fontWeight: '600' })
  .hover()
    .background({ color: '#4f46e5' })
  .end()
  .$el('btn');

Use in your component

import { button } from './button.chain';

export function App() {
  return <button className={button}>Click Me</button>;
}

Why ChainCSS?

Unlike traditional CSS-in-JS libraries, ChainCSS is built around a compiler architecture.

Your styles become an Intermediate Representation (IR), pass through multiple optimization stages, and are emitted into deterministic outputs such as CSS, Atomic CSS, Tailwind configuration, Design Tokens, or Figma tokens.

This keeps the runtime extremely small while enabling sophisticated compile-time analysis and optimization.


Compiler Architecture

ChainCSS is built as a compiler platform—not simply a styling library.

| Component | Purpose | Benefit | |-----------|---------|---------| | Collector | Collects fluent style definitions | Unified authoring model | | Intermediate Representation (IR) | Canonical representation of every style | Enables compiler transformations | | Dependency Graph | Tracks relationships between rules, components, animations and tokens | Incremental compilation & graph analysis | | Symbol Table | Stores semantic compiler information | Efficient analysis and lookups | | Pass Scheduler | Orders compiler passes based on dependencies | Extensible and deterministic compilation | | Compiler Pipeline | Normalize → Validate → Analyze → Optimize → Lower | Independent, testable compiler passes | | Persistent Cache | Stores compiler state between builds | Faster rebuilds, survives process restarts | | Incremental Compiler | Recompiles only affected nodes via graph analysis | Efficient watch mode | | Emitter Registry | Generates multiple outputs from the same IR | CSS, Atomic CSS, Tailwind, Tokens, Figma, Graph JSON | | Plugin System | Extends any compiler phase | Custom analysis, validation, optimization and emitters |


Features

Structured Styling API

Group related CSS properties into 16 expressive typed methods instead of large flat objects.

chain()
  .flex({ direction: 'column', align: 'center', gap: 16 })
  .box({ p: 24, br: 12, w: '100%' })
  .background({ color: '#6366f1' })
  .typography({ color: 'white', fw: 600 })
  .transition({ tr: 'all 0.2s ease' })
  .hover()
    .background({ color: '#4f46e5' })
    .transform({ custom: 'scale(1.02)' })
  .end()
  .$el('btn')

Intelligent Unit Inference

Numeric values automatically receive CSS units where appropriate. Knows which properties are unitless (lineHeight, opacity, zIndex, fontWeight, etc.).

chain().box({ width: 300, borderRadius: 8 })

width: 300px; border-radius: 8px;

Transform Composition

Individual transform properties are composed into a single transform declaration in the correct order.

chain().box({ x: 10, y: 20, rotate: 45 })

transform: translateX(10px) translateY(20px) rotate(45deg);

Mixed Static + Dynamic Rendering

ChainCSS is the only library that allows per-property mixing of static and dynamic styles in a single definition. Static values compile to zero-runtime CSS. Dynamic values become CSS custom properties. Both use the same fluent API—no separate recipes, no different syntax, no compromises.

export const btn = chain.dynamic()
  .box({ padding: '12px 24px', borderRadius: 8 })                          // -> static CSS
  .background({ color: (ctx) => ctx.isActive ? '#6366f1' : '#a5b4fc' })    // -> runtime var
  .shadow({ box: (ctx) => ctx.isActive
    ? '0 8px 25px rgba(99,102,241,0.4)'
    : '0 2px 8px rgba(0,0,0,0.1)'
  })
  .$el('btn')

10 properties are static. 2 are dynamic. The CSS file contains 12 declarations—10 real values and 2 var() placeholders. The JS file contains only the 2 functions that actually need runtime evaluation.

/* Generated CSS */
.chain-btn {
  padding: 12px 24px;
  border-radius: 8px;
  background-color: var(--chain-btn-background-color);
  box-shadow: var(--chain-btn-box-shadow);
}
import { useChainStyles } from 'chaincss/runtime'
import { btn } from './button.chain'

function Button({ isActive }: { isActive: boolean }) {
  const { classes, styleVars } = useChainStyles({ btn }, { isActive })
  return <button className={classes.btn} style={styleVars}>Click</button>
}

Framework Adapters

useChainStyles returns { classes, styleVars } in every framework. Each adapter uses the framework's native reactivity system.

| Framework | Hook | State Change | |-----------|------|-------------| | React | useChainStyles(styles, deps) | Re-renders via useMemo deps | | Vue | useChainStyles(styles, refs) | Auto-unwraps ref() values, watches changes | | Svelte | useChainStyles(styles, stores) | Subscribes to store changes | | Solid | useChainStyles(styles, signals) | Auto-tracks signal access via createMemo |

Token Dependency Graph

Tokens are relationships—not just variables. Changing one token automatically updates derived colors, harmony palettes, and contrast colors. All computed in the OKLCH color space for perceptual accuracy.

tokens: {
  relationships: [
    { type: 'derived', source: 'colors.primary.500', target: 'colors.primary.100', method: 'mix-white 80%' },
    { type: 'derived', source: 'colors.primary.500', target: 'colors.primary.600', method: 'shade 20%' },
    { type: 'contrast', foreground: 'colors.text.onPrimary', background: 'colors.primary.500', target: 4.5, autoFix: 'auto' },
    { type: 'harmony', source: 'colors.primary.500', targets: ['colors.accent.500', 'colors.accent.300'], rule: 'complementary' }
  ]
}

Semantic Intent System

Design with intent, not implementation.

Instead of repeatedly describing how an element should look using individual CSS properties, ChainCSS lets you describe what the element is or what design concept it represents.

chain()
  .intents(['card'])
  .$el('product-card')

The compiler resolves the intent into its underlying style definition and passes the result through the normal ChainCSS compilation pipeline.

"card"
  ↓
Intent Registry
  ↓
Intent Resolution
  ↓
Style IR
  ↓
Compiler Pipeline
  ↓
Optimized CSS

Built-in intent vocabulary

ChainCSS ships with built-in intents covering common layout, component, semantic, and interaction concepts.

| Category | Built-in Intents | |----------|------------------| | Layout | center-content, stack, sidebar-layout, grid-list | | Component | card, button-primary, button-secondary, input-field, modal, tooltip | | Semantic | hero-section, sticky-header | | Interaction | hover-lift, focus-ring |

For example, card expands into properties such as display: flex; flex-direction: column; overflow: hidden; including generated interaction states and accessibility metadata.

User-defined intents

The built-in vocabulary is not a closed list. Applications can introduce their own design vocabulary through chaincss.config.ts:

export default defineConfig({
  intents: {
    glass: {
      name: 'glass',
      category: 'visual',
      description: 'Frosted glass effect',
      properties: {
        background: 'rgba(255,255,255,0.1)',
        backdropFilter: 'blur(10px)',
        border: '1px solid rgba(255,255,255,0.2)',
        borderRadius: '12px',
      }
    }
  }
});

The intent can then be used directly:

chain()
  .intents(['glass'])
  .$el('panel')

Composite intents

Intents can be composed from other intents:

intents: {
  premium: {
    name: 'premium',
    category: 'composite',
    resolve: () => ({
      expandsTo: ['card', 'center-content'],
    })
  }
}
chain()
  .intents(['premium'])
  .$el('premium-card')
premium
 ├── card
 └── center-content

Multiple intents

chain()
  .intents(['center-content', 'sticky-header'])
  .box({ minHeight: '400px' })
  .$el('hero')

Natural-language intent descriptions

chain()
  .describe('glass elevated spacious')
  .$el('navbar')

The description is parsed into intent names and resolved through the same intent registry:

"glass elevated spacious"
         ↓
     intent parser
         ↓
["glass", "elevated", "spacious"]
         ↓
   intent registry
         ↓
     Style IR
         ↓
      CSS output

Intent System — Complete Feature Set

ChainCSS includes a four-phase intent system that turns design vocabulary into production CSS.

Phase 1: Relationships & Constraints

Intents know how they relate to each other.

chain()
  .intents(['card', 'compact'])
  .$el('card')
  • requires — Auto-adds required intents (card requires rounded)
  • conflicts — Prevents invalid combinations (compact conflicts with spacious)
  • enhances — Suggests great combinations (card enhances elevated, glass)
  • maxCombinations — Limits stacking
  • priority — Resolution order

Phase 2: Themes & Variants

Intents adapt to context.

chain()
  .intents(['card'])
  .$el('card')

Compiles both light and dark CSS:

/* Light */
.chain-card { background: #ffffff; }

/* Dark — automatically generated */
[data-theme="dark"] .chain-card { background: #1e293b; }

Variants provide named alternatives:

chain()
  .intents(['card'])
  .$el('premium-card')
// variant: 'premium' → gradient background

Phase 3: Composition Patterns

Intents compose into more complex components.

chain()
  .intents(['premium-card'])
  .$el('premium-card')

premium-card expands to:

card + glass + elevated

With conditional behavior:

// Dark mode automatically:
// + glow
// - elevated

Phase 4: Natural Language

Describe designs in plain English.

chain()
  .describe('dark premium card')
  .$el('premium-dark-card')

The deterministic parser:

  • Maps synonyms (frostedglass)
  • Detects themes (dark, light, high-contrast)
  • Detects variants (premium, outlined, success)
  • Resolves composition (premium cardpremium-card)
  • Ignores stop words (a, the, with, and)

Intent Resolution Pipeline

.describe('dark premium card')
    ↓
Parser: intents=['premium-card'], theme='dark'
    ↓
Composition: premium-card → card + glass + elevated
    ↓
Conditions: dark → + glow, - elevated
    ↓
Relationships: card requires rounded
    ↓
Themes: apply dark overrides
    ↓
Tokens: resolve $colors.*
    ↓
CSS: [data-theme="dark"] .chain-premium-card { ... }

Intent Catalog

| Phase | Feature | Count | |-------|---------|-------| | Base | Built-in intents | 58+ | | Phase 1 | Relationship rules | 50+ relationships | | Phase 2 | Theme variants | dark, high-contrast | | Phase 2 | Named variants | premium, outlined, success, danger, warning | | Phase 3 | Composition intents | premium-card, premium-button, glass-panel, hero-banner, modal-glass, input-group | | Phase 4 | Natural language | Dictionary + synonyms + stop words |

Accessibility Compilation

Six WCAG checks run during compilation—not in CI, not in the browser. Milliseconds, not seconds.

| Check | Severity | Criterion | Auto-Fix | |-------|----------|-----------|----------| | Contrast ratio | Error | 1.4.3 AA (4.5:1) | Binary search in OKLCH | | Font size minimum | Warning | 1.4.4 AA (12px) | max(12px, value) | | Touch target size | Warning | 2.5.8 AA (44x44px) | min-width/height or ::after | | Focus visible | Error | 2.4.7 AA | Auto-inject :focus-visible | | Reduced motion | Warning | 2.3.3 AAA | Wrap in @media query | | Hover without focus | Warning | 1.4.13 AA | Mirror to :focus-visible |

chaincss check --strict    # CI gate — fails on errors
chaincss audit --fix --write  # Auto-fix and write to token files

Compile-Time Optimization

Nine optimization passes run on every stylesheet:

| Pass | What It Does | |------|-------------| | AST Optimizer | Simplifies calc() expressions, constant folding, identity removal | | Duplicate Declaration Detector | Removes overridden declarations, preserves intentional fallbacks | | Dead Code Eliminator | Removes unreferenced rules via graph analysis | | CSS Compressor | Shortens hex colors, removes zero units, compresses box-model shorthands | | Accessibility Optimizer | Auto-fixes font sizes, touch targets, focus rings | | Atomic Extractor | Extracts repeated declarations (3+ usages) to utility classes | | Media Query Packer | Merges identical queries via AST comparison, sorts by breakpoint | | Source Optimizer | Deduplicates identical rules across files | | Specificity Sorter | Orders rules by CSS specificity |

Relationship Macros (100+)

Express CSS relationships rather than selectors. Zero runtime. All outputs are pure CSS.

| Instead of | Write | Category | |---|---|---| | .group:has(> :hover) > &:not(:hover) | .peerDim() | Interaction | | &:has(> :nth-child(3)) | .hasCount({ count: 3 }) | Layout | | &:focus-within label, &:has(input:not(:placeholder-shown)) label | .entangleFocus() | Accessibility | | Full scroll-driven animation setup | .entangle('scroll', { opacity: '0->1', y: '20px->0' }) | Animation | | 8+ properties for glass morphism | .glass() | Effects | | Complex grid with subgrid + container queries | .bento() | Layout |

Multi-Target Emission

A single .chain.ts file compiles to multiple output formats simultaneously from the same IR.

chaincss build --target css,atomic-css,tailwind,design-tokens,figma,graph-json

| Target | Output | Use Case | |--------|--------|----------| | css | styles.css | Standard CSS | | atomic-css | atomic.css | Utility-first atomic classes | | tailwind | tailwind.config.generated.js | Tailwind theme extension | | design-tokens | design-tokens.json | Platform-agnostic token export | | figma | figma-tokens.json | Round-trip to Figma Tokens Studio | | graph-json | chaincss-graph.json | Dependency graph visualization |

Component Variants (Recipes)

Type-safe component variants with compound conditions. All variants compile at build time.

export const buttonVariants = recipe({
  base: chain().box({ p: '8px 16px', br: 8 }).$el('btn'),
  variants: {
    color: {
      primary: chain().background('#6366f1').typography({ color: 'white' }).$el(),
      secondary: chain().background('#48bb78').$el(),
      danger: chain().background('#f56565').$el(),
    },
    size: {
      sm: chain().box({ p: '4px 8px' }).typography({ fs: 12 }).$el(),
      md: chain().box({ p: '8px 16px' }).typography({ fs: 14 }).$el(),
      lg: chain().box({ p: '12px 24px' }).typography({ fs: 16 }).$el(),
    }
  },
  defaultVariants: { color: 'primary', size: 'md' },
})

buttonVariants({ color: 'secondary', size: 'lg' })  // -> merged StyleDefinition

Figma Integration

Bidirectional sync: designers change colors in Figma → Tokens Studio pushes to GitHub → GitHub Action runs entanglement → derived tokens update → contrast auto-fixes.

chaincss figma init --repo org/design-tokens --fileId abc123
chaincss entanglement --input tokens.json --watch --fix --figma

Dev Server with HMR

Zero-config development server with hot module replacement, build error overlay, and persistent compiler state.

chaincss dev --port 3000
  • Instant HMR: CSS changes stream via SSE, no page reload
  • Build error overlay: Compilation errors injected into the page
  • Persistent state: Survives restarts for cold-start incremental builds
  • Compiler stats: Real-time metrics at /__chaincss_stats

CLI Commands

chaincss init
chaincss create app my-app --template react --pm pnpm
chaincss dev --port 3000
chaincss watch --verbose
chaincss build --minify --atomic --persistent
chaincss build --target css,tailwind,design-tokens,figma,graph-json
chaincss check --strict
chaincss audit --fail-on AA --fix --write
chaincss entanglement --input tokens.json --watch --fix
chaincss figma init --repo org/design-tokens
chaincss cache stats
chaincss cache validate
chaincss timeline list
chaincss timeline diff --snapshot1 0 --snapshot2 5

Supported Frameworks

| Framework | Static | Dynamic | Adapter | |-----------|:------:|:-------:|---------| | React | Yes | Yes | useChainStyles + useMemo | | Vue | Yes | Yes | useChainStyles + ref/watch | | Svelte | Yes | Yes | useChainStyles + stores | | Solid | Yes | Yes | useChainStyles + signals | | Next.js | Yes | Yes | Server + Client components | | Vanilla HTML | Yes | Yes | styleInjector |


Build Integrations

  • Vite — Plugin with HMR, virtual CSS, persistent state
  • Next.js — Server Component + Client Component support
  • Webpack — Plugin with incremental compilation
  • PostCSS — Drop-in plugin for existing pipelines
  • CLI — Full-featured standalone build tool

Performance

| Rules | Compile Time | Output Size | |-------|--------------|-------------| | 5 | 0.54 ms | 0.4 KB | | 50 | 4.80 ms | 11.3 KB | | 500 | 93.06 ms | 133.0 KB | | 2,000 | 1,709.92 ms | 533.2 KB |

Measurements taken on a Lenovo G560 (Node.js v22.23.1, 4 CPUs, 4GB RAM).


Philosophy

ChainCSS approaches styling the same way modern language compilers approach source code.

Instead of treating CSS as strings, it treats styles as structured data that can be analyzed, validated, optimized, transformed, cached, and emitted into multiple targets.

The objective is to provide the ergonomics of a fluent styling API while leveraging compiler techniques typically found in tools such as TypeScript, Babel, SWC, and LLVM.


License

MIT

Author: Rommel Edorot Caneos

Contact | Website

GitHub