Tasty
Design-system styling engine and DSL that generates conflict-free CSS using mutually exclusive selectors, with runtime or static extraction.
Install / Use
/learn @tenphi/TastyREADME
Tasty is a styling engine for design systems that generates deterministic CSS for stateful components.
It compiles state maps into mutually exclusive selectors, so for a given property and component state, one branch wins by construction instead of competing through cascade and specificity.
That is the core guarantee: component styling resolves from declared state logic, not from source-order accidents or specificity fights.
Tasty fits best when you are building a design system or component library with intersecting states, variants, tokens, sub-elements, responsive rules, and extension semantics that need to stay predictable over time.
On top of that foundation, Tasty gives teams a governed styling model: a CSS-like DSL, tokens, recipes, typed style props, sub-elements, and multiple rendering modes.
- New here? Start with Comparison if you are evaluating fit.
- Adopting Tasty? Read the Adoption Guide.
- Want the mechanism first? Jump to How It Actually Works.
- Ready to build? Go to Getting Started.
Why Tasty
- Deterministic composition, not cascade fights — Stateful styles resolve from the state map you declared, not from selector competition. See How It Actually Works.
- Built for design-system teams — Best fit for reusable component systems with complex state interactions.
- A governed styling model, not just syntax sugar — Design-system authors define the styling language product teams consume.
- DSL that still feels like CSS — Familiar property names, less selector boilerplate. Start with the Style DSL, then use Style Properties as the handler reference.
Supporting capabilities
- Typed style props and mod props —
stylePropsexposes selected CSS properties as typed React props (<Space flow="row" gap="2x">);modPropsdoes the same for modifier keys (<Button isLoading size="large">). Both support state maps and full TypeScript autocomplete. See Style Props and Mod Props. - Runtime, SSR, and zero-runtime options — Use
tasty()for runtime React components, add SSR integrations when your framework renders that runtime on the server, or usetastyStatic()when you specifically want build-time extraction instead of runtime styling. - Broad modern CSS coverage — Media queries, container queries,
@supports,:has(),@starting-style,@property,@keyframes, and more. Features that do not fit the component model (such as@layerand!important) are intentionally left out. - Performance and caching — Runtime mode injects CSS on demand, reuses chunks aggressively, and relies on multi-level caching so large component systems stay practical.
- TypeScript-first and AI-friendly — Style definitions are declarative, structurally consistent, and fully typed, which helps both humans and tooling understand advanced stateful styles without hidden cascade logic.
Why It Exists
Modern component styling becomes fragile when multiple selectors can still win for the same property. Hover, disabled, theme, breakpoint, parent state, and root state rules start competing through specificity and source order.
Tasty replaces that competition with explicit state-map resolution. Each property compiles into mutually exclusive branches, so component styling stays deterministic as systems grow. For the full mechanism, jump to How It Actually Works.
Installation
pnpm add @tenphi/tasty
Requirements:
- Node.js 20+
- React 18+ (peer dependency for the React entry points)
pnpm,npm, oryarn
Other package managers:
npm add @tenphi/tasty
yarn add @tenphi/tasty
Start Here
For the fuller docs map beyond the quick routes above, start here:
- Comparison — read this first if you are evaluating whether Tasty fits your team's styling model
- Adoption Guide — understand who Tasty is for, where it fits, and how to introduce it incrementally
- Getting Started — the canonical onboarding path: install, first component, optional shared
configure(), ESLint, editor tooling, and rendering mode selection - Style rendering pipeline — see the selector model behind deterministic style resolution
- Docs Hub — choose docs by role and task: runtime, zero-runtime, runtime SSR integration, design-system authoring, internals, and debugging
- Methodology — the recommended component model and public API conventions for design-system code
Quick Start
Create a styled component
import { tasty } from '@tenphi/tasty';
const Card = tasty({
as: 'div',
styles: {
display: 'flex',
flow: 'column',
padding: '24px',
gap: '12px',
fill: 'white',
color: '#222',
border: '1px solid #ddd',
radius: '12px',
},
});
// Just a React component
<Card>Hello World</Card>
Every value maps to CSS you'd recognize. This example is intentionally a simple first contact, not a tour of the whole DSL.
When you want a more design-system-shaped authoring model, Tasty also supports built-in units, tokens, recipes, state aliases, and color values such as okhsl(...) without extra runtime libraries.
Use configure() when you want to define shared tokens, state aliases, recipes, or other conventions for your app or design system. For a fuller onboarding path, follow Getting Started.
Add state-driven styles
const Button = tasty({
as: 'button',
styles: {
padding: '1.5x 3x',
fill: {
'': '#primary',
':hover': '#primary-hover',
':active': '#primary-pressed',
'[disabled]': '#surface',
},
color: {
'': '#on-primary',
'[disabled]': '#text.40',
},
cursor: {
'': 'pointer',
'[disabled]': 'not-allowed',
},
transition: 'theme',
},
});
State keys support pseudo-classes first (:hover, :active), then modifiers (theme=danger), attributes ([disabled]), media/container queries, root states, and more. Tasty compiles them into exclusive selectors automatically.
Extend any component
import { Button } from 'my-ui-lib';
const DangerButton = tasty(Button, {
styles: {
fill: {
'': '#danger',
':hover': '#danger-hover',
},
},
});
Child styles merge with parent styles intelligently — state maps can extend or replace parent states per-property.
Optional: configure shared conventions
import { configure } from '@tenphi/tasty';
configure({
states: {
'@mobile': '@media(w < 768px)',
'@tablet': '@media(w < 1024px)',
'@dark': '@root(schema=dark) | (!@root(schema) & @media(prefers-color-scheme: dark))',
},
recipes: {
card: { padding: '4x', fill: '#surface', radius: '1r', border: true },
},
});
Use configure() once when your app or design system needs shared aliases, tokens, recipes, or parser extensions. Predefined states turn complex selector logic into single tokens, so teams can write @mobile instead of repeating media query expressions in every component.
Props as the public API
styleProps exposes selected CSS properties as typed React props, and modProps does the same for modifier keys. Together they let design systems define a governed, typed component API without wrapper elements or styles overrides:
<Space flow="row" gap="2x" placeItems="center">
<Button isLoading size="large" placeSelf="end">Submit</Button>
</Space>
See Style Props and Mod Props below, or the full reference in Runtime API.
Choose a Styling Approach
Once you understand the component model, pick the rendering mode that matches your app.
| Approach | Entry point | Best for | Trade-off |
|----------|-------------|----------|-----------|
| Runtime | @tenphi/tasty | Interactive apps with reusable stateful components and design systems | Full feature set; CSS is generated on demand at runtime |
| Zero-runtime | @tenphi/tasty/static | Static sites, SSG, landing pages | Requires the Babel plugin; no component-level styleProps or runtime-only APIs |
If your framework can execute runtime React code on the server, you can also add SSR on top of runtime with @tenphi/tasty/ssr/*. This uses the same tasty() pipeline, but collects CSS during server rendering and hydrates the cache on the client. That is the model for Next.js, generic React SSR, and Astro islands. See Getting Started, Zero Runtime, and Server-Side Rendering.
How It Actually Works
This is the core idea that makes everything else possible.
For the end-to-end architecture — parsing state keys, building exclusive conditions, merging by output, and materializing selectors and at-rules — see Style rendering pipeline.
