DEV Community

Alex Spinov
Alex Spinov

Posted on

Vanilla Extract Has a Free API You're Not Using

Vanilla Extract generates zero-runtime CSS from TypeScript at build time. You get full type safety for your styles without any runtime cost.

The Free APIs You're Missing

1. Sprinkles — Atomic CSS with Type Safety

// 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", "grid", "block"],
    flexDirection: ["row", "column"],
    gap: { 0: 0, 1: "4px", 2: "8px", 3: "16px", 4: "24px" },
    padding: { 0: 0, 1: "4px", 2: "8px", 3: "16px", 4: "24px" },
  },
});

export const sprinkles = createSprinkles(responsiveProperties);

// Usage: className={sprinkles({ display: { mobile: "block", desktop: "flex" }, gap: 3 })}
Enter fullscreen mode Exit fullscreen mode

Tailwind-like atomic CSS with full TypeScript autocomplete. Invalid values are compile errors.

2. Recipes — Component Variant API

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

export const button = recipe({
  base: {
    borderRadius: 8,
    fontWeight: 600,
    border: "none",
    cursor: "pointer",
    transition: "all 0.2s",
  },
  variants: {
    color: {
      primary: { background: "#3b82f6", color: "white" },
      secondary: { background: "#6b7280", color: "white" },
      danger: { background: "#ef4444", color: "white" },
    },
    size: {
      sm: { padding: "6px 12px", fontSize: 14 },
      md: { padding: "8px 16px", fontSize: 16 },
      lg: { padding: "12px 24px", fontSize: 18 },
    },
  },
  compoundVariants: [
    { variants: { color: "primary", size: "lg" }, style: { boxShadow: "0 4px 12px rgba(59,130,246,0.4)" } },
  ],
  defaultVariants: { color: "primary", size: "md" },
});

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

3. createTheme() — Type-Safe Theming

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

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

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

export const darkTheme = createTheme(vars, {
  color: { brand: "#60a5fa", text: "#f5f5f5", bg: "#0a0a0a" },
  space: { sm: "4px", md: "8px", lg: "16px" },
});

// Use: style({ color: vars.color.text }) — works in both themes
Enter fullscreen mode Exit fullscreen mode

4. Dynamic Styles — CSS Variables at Runtime

import { createVar, style, assignInlineVars } from "@vanilla-extract/css";

const progressVar = createVar();

export const progressBar = style({
  width: progressVar,
  height: 8,
  background: "#3b82f6",
  borderRadius: 4,
  transition: "width 0.3s",
});

// React: <div className={progressBar} style={assignInlineVars({ [progressVar]: `${progress}%` })} />
Enter fullscreen mode Exit fullscreen mode

5. globalStyle() — Scoped Global Styles

import { globalStyle } from "@vanilla-extract/css";

globalStyle("html, body", {
  margin: 0,
  fontFamily: "system-ui, sans-serif",
});

globalStyle(`${container} > a`, {
  color: vars.color.brand,
  textDecoration: "none",
});
Enter fullscreen mode Exit fullscreen mode

Getting Started

npm install @vanilla-extract/css @vanilla-extract/vite-plugin
Enter fullscreen mode Exit fullscreen mode

Need data from any website delivered as clean JSON? I build production web scrapers that handle anti-bot, proxies, and rate limits. 77 scrapers running in production. Email me: Spinov001@gmail.com

Check out my awesome-web-scraping list for the best scraping tools and resources.

Top comments (0)