Tasty logoTasty
Get Started
Tasty logov1.0

The styling engine built for design systems

Deterministic CSS generation. State‑aware DSL. Zero specificity conflicts. Ever.

Why Tasty

Everything you need for styling at scale

Deterministic at Any Scale

Exclusive selector generation eliminates the entire class of cascade and specificity bugs. Refactor freely.

DSL That Feels Like CSS

Property names you already know with syntax sugar that removes boilerplate. Learn in minutes, not days.

Design‑System Native

Color tokens, spacing units, typography presets, and recipes are first‑class primitives, not afterthoughts.

State‑Aware Styling

Media queries, container queries, @supports, :has() — all compose in one declarative state map.

Sub‑Element Styling

Style inner elements from the parent definition. No extra components, no CSS leakage.

SSR & Zero‑Runtime

Runtime, zero‑runtime, or SSR with zero‑cost hydration. Same DSL, same tokens, same output.

How It Actually Works

Every state mapping compiles into mutually exclusive selectors

Tasty DSL

Input
const Button = tasty({
  as: 'button',
  styles: {
    fill: {
      '': '#purple',
      ':hover': '#purple-04',
      ':active': '#purple-05',
    },
    color: '#white',
    padding: '1.5x 3x',
    radius: 'round',
    border: 'none',
    cursor: 'pointer',
    transition: 'theme',
  },
});

Exclusive CSS Selectors

Output
/* Default: not hovered and not active */
.t0.t0:not(:hover):not(:active) {
  background: var(--purple-color);
}

/* Hovered but not active */
.t0.t0:hover:not(:active) {
  background: var(--purple-04-color);
}

/* Active */
.t0.t0:active {
  background: var(--purple-05-color);
}

/* Base styles (always applied) */
.t0.t0 {
  color: white;
  padding: 12px 24px;
  border-radius: 9999px;
  border: none;
  cursor: pointer;
  transition: all var(--transition-duration)
    var(--transition-timing-function);
}

Tasty DSL

Input
// Define a reusable state alias
configure({
  states: {
    '@dark': '@root(schema=dark) | (!@root(schema) & @media(prefers-color-scheme: dark))',
  },
});

// Use the alias in styles
const Text = tasty({
  // You can also define `@dark` here
  styles: {
    color: {
      '': '#text',
      '@dark': '#text-on-dark',
    },
  },
});

Exclusive CSS Selectors

Output
/* Branch 1: Explicit dark schema */
:root[data-schema="dark"] .t0.t0 {
  color: var(--text-on-dark-color);
}

/* Branch 2: No schema attribute + OS prefers dark */
@media (prefers-color-scheme: dark) {
  :root:not([data-schema]) .t0.t0 {
    color: var(--text-on-dark-color);
  }
}

/* Default: no schema + OS does not prefer dark */
@media (not (prefers-color-scheme: dark)) {
  :root:not([data-schema="dark"]) .t0.t0 {
    color: var(--text-color);
  }
}

/* Default: schema is set but not dark */
:root:not([data-schema="dark"])[data-schema] .t0.t0 {
  color: var(--text-color);
}

No two rules can match at the same time. No specificity arithmetic. No source‑order dependence.

Components compose and extend without collisions.

Try in Playground

Design Token Support

Specify spacing, typography, and WCAG‑compliant color palettes with a unified token system

Core Tokens
useGlobalStyles('body', {
  // Base tokens
  '$gap': '8px',
  '$radius': '10px',
  '$card-radius': '20px',
  '$border-width': '1px',
  '$outline-width': '2px',
  '$bold-font-weight': 600,
  '$transition': '0.2s',
  '$content-width': '1200px',

  // Color tokens (OKHSL)
  '#success': 'okhsl(145 75% 55%)',
  '#warning': 'okhsl(70 80% 60%)',
  '#danger': 'okhsl(25 85% 55%)',
  '#info': 'okhsl(215 70% 55%)',
  '#neutral': 'okhsl(210 10% 50%)',
});
Palette Color Tokens (Glaze)
const violet = glaze(272, 75);

violet.colors({
  surface: {
    lightness: 98, saturation: 0.2,
  },
  text: {
    base: 'surface', lightness: '-62',
    contrast: 'AAA', saturation: 0.08,
  },
  'accent-surface': {
    lightness: 52, mode: 'fixed',
  },
  'shadow-md': {
    type: 'shadow', bg: 'surface',
    fg: 'text', intensity: 12,
  },
});

Tasty natively supports OKHSL — a perceptually uniform color space where equal steps in lightness produce equal changes in perceived contrast, making palette generation predictable by design.

Need full color palettes with automatic dark mode, high‑contrast schemes, and WCAG‑compliant contrast ratios? Use Glaze — a zero‑dependency companion library that generates production‑ready color palettes.

See It In Action

Real patterns from production codebases

State Maps

Style any property based on pseudo‑classes, data attributes, media queries, and more.

const Button = tasty({
  as: 'button',
  styles: {
    fill: {
      '': '#primary-accent-surface',
      ':hover': '#primary-icon',
      ':active': '#primary-text',
      '[disabled]': '#primary-disabled',
    },
    cursor: {
      '': 'pointer',
      '[disabled]': 'not-allowed',
    },
    transition: 'theme',
  },
});

Responsive Design

Define breakpoints once, use @mobile and @tablet as states anywhere.

configure({
  states: {
    '@tablet': '@media(640px <= w < 1024px)',
    '@mobile': '@media(w < 640px)',
  },
});

const Layout = tasty({
  styles: {
    display: 'grid',
    gridColumns: {
      '': '1sf 1sf 1sf',
      '@tablet': '1sf 1sf',
      '@mobile': '1sf',
    },
    gap: {
      '': '4x',
      '@mobile': '2x',
    },
    padding: {
      '': '8x 4x',
      '@mobile': '4x 2x',
    },
  },
});

Sub‑Elements

Style inner elements from the parent. Typed sub‑components via the elements prop.

const Card = tasty({
  styles: {
    padding: '4x',
    radius: '1cr',
    border: true,
    Title: {
      $: '>',
      preset: 'h3',
      color: '#primary-accent-text',
    },
    Content: {
      $: '>',
      preset: 't2',
      color: '#primary-text',
    },
  },
  elements: { Title: 'h3', Content: 'div' },
});

// Usage:
// <Card>
//   <Card.Title>Hello</Card.Title>
//   <Card.Content>World</Card.Content>
// </Card>

Configuration

Set up global states, custom units, functions, and reusable style recipes — all in one place.

import { configure } from '@tenphi/tasty';

configure({
  states: {
    '@dark': '@root(theme=dark) | @media(prefers-color-scheme: dark)',
    '@mobile': '@media(w < 640px)',
  },
  units: {
    col: (n) => `${(n / 12) * 100}%`,
    gap: '4px',
  },
  funcs: {
    fluid: ([min, max]) =>
      `clamp(${min.output}, 2.5vw + 1rem, ${max.output})`,
  },
  recipes: {
    card: {
      padding: '3x',
      fill: '#surface',
      radius: '1cr',
      border: true,
      shadow: '0 1x 3x #shadow-sm',
    },
  },
});

Complete Ecosystem

Tools that complete the picture

Start building with Tasty

One install. Zero config. Ship beautiful, accessible UIs today.

$ pnpm add @tenphi/tasty