DEV Community

Alex Spinov
Alex Spinov

Posted on

Vanilla Extract Has a Free API That Makes Type-Safe CSS a Reality

Vanilla Extract is a zero-runtime CSS-in-TypeScript framework. Write styles in .css.ts files, get static CSS with full type safety.

Basic Styles

// styles.css.ts
import { style, globalStyle } from "@vanilla-extract/css";

export const container = style({
  maxWidth: "1200px",
  margin: "0 auto",
  padding: "24px",
});

export const card = style({
  background: "white",
  borderRadius: "12px",
  padding: "24px",
  boxShadow: "0 4px 6px rgba(0,0,0,0.1)",
  ":hover": {
    boxShadow: "0 10px 20px rgba(0,0,0,0.15)",
    transform: "translateY(-2px)",
  },
  "@media": {
    "(max-width: 768px)": {
      padding: "16px",
    },
  },
});

// Usage
import { container, card } from "./styles.css";
<div className={container}><div className={card}>Content</div></div>
Enter fullscreen mode Exit fullscreen mode

Sprinkles: Atomic CSS API

// sprinkles.css.ts
import { defineProperties, createSprinkles } from "@vanilla-extract/sprinkles";

const responsiveProperties = defineProperties({
  conditions: {
    mobile: {},
    tablet: { "@media": "(min-width: 768px)" },
    desktop: { "@media": "(min-width: 1024px)" },
  },
  defaultCondition: "mobile",
  properties: {
    display: ["none", "flex", "block", "grid"],
    flexDirection: ["row", "column"],
    gap: { 0: "0", 1: "4px", 2: "8px", 3: "12px", 4: "16px", 6: "24px", 8: "32px" },
    padding: { 0: "0", 1: "4px", 2: "8px", 3: "12px", 4: "16px", 6: "24px" },
    fontSize: { sm: "14px", md: "16px", lg: "20px", xl: "24px" },
  },
});

const colorProperties = defineProperties({
  conditions: { light: {}, dark: { "@media": "(prefers-color-scheme: dark)" } },
  defaultCondition: "light",
  properties: {
    color: { primary: "#3b82f6", secondary: "#64748b", text: "#1e293b" },
    background: { surface: "white", muted: "#f1f5f9", dark: "#0f172a" },
  },
});

export const sprinkles = createSprinkles(responsiveProperties, colorProperties);

// Usage — fully type-safe!
const className = sprinkles({
  display: { mobile: "block", desktop: "flex" },
  gap: 4,
  padding: 6,
  color: "primary",
});
Enter fullscreen mode Exit fullscreen mode

Recipes: Component Variants

import { recipe } from "@vanilla-extract/recipes";

export const button = recipe({
  base: {
    borderRadius: "8px",
    fontWeight: 600,
    cursor: "pointer",
    transition: "all 0.2s",
  },
  variants: {
    color: {
      primary: { background: "#3b82f6", color: "white" },
      danger: { background: "#ef4444", color: "white" },
    },
    size: {
      sm: { padding: "8px 16px", fontSize: "14px" },
      md: { padding: "12px 24px", fontSize: "16px" },
      lg: { padding: "16px 32px", fontSize: "18px" },
    },
  },
  defaultVariants: { color: "primary", size: "md" },
});

// Usage
<button className={button({ color: "danger", size: "lg" })}>Delete</button>
Enter fullscreen mode Exit fullscreen mode

Theme API

import { createTheme, createThemeContract } from "@vanilla-extract/css";

const vars = createThemeContract({
  color: { brand: null, text: null, surface: null },
  space: { sm: null, md: null, lg: null },
});

export const lightTheme = createTheme(vars, {
  color: { brand: "#3b82f6", text: "#1e293b", surface: "#ffffff" },
  space: { sm: "8px", md: "16px", lg: "32px" },
});

export const darkTheme = createTheme(vars, {
  color: { brand: "#60a5fa", text: "#f1f5f9", surface: "#0f172a" },
  space: { sm: "8px", md: "16px", lg: "32px" },
});
Enter fullscreen mode Exit fullscreen mode

Type-safe styling for data apps? My Apify tools power the data layer.

Custom solution? Email spinov001@gmail.com

Top comments (1)

Collapse
 
9opsec profile image
9opsec

1642 posts in 11 days seem to be a bit excessive. I hope you aren't a bot. This duplicate content is absolutely flooding the RSS feed.