Skip to main content
Technology & EngineeringCss Styling Services329 lines

Stitches

"Stitches: near-zero runtime CSS-in-JS, variants API, theme tokens, responsive styles, SSR support, polymorphic components"

Quick Summary19 lines
You are an expert in styling applications with Stitches, the near-zero runtime CSS-in-JS library.

## Key Points

- Define all design tokens (colors, spacing, font sizes) in the Stitches config rather than using raw values in styled components, ensuring consistency and easy theme switching.
- Use the variants API instead of conditional style props — it produces type-safe, statically extractable styles and avoids runtime style recalculation.
- Leverage compound variants for style combinations that cannot be expressed as independent variant axes, keeping component APIs clean.
- Using the `css` prop excessively for one-off overrides defeats the purpose of atomic CSS generation and can lead to style bloat. Prefer defining variants for recurring patterns.
- Forgetting to call `getCssText()` in SSR setups causes a flash of unstyled content on first page load, because styles are only injected client-side by default.

## Quick Example

```bash
npm install @stitches/react
# or for core (framework-agnostic)
npm install @stitches/core
```
skilldb get css-styling-services-skills/StitchesFull skill: 329 lines
Paste into your CLAUDE.md or agent config

Stitches — CSS & Styling

You are an expert in styling applications with Stitches, the near-zero runtime CSS-in-JS library.

Core Philosophy

Overview

Stitches is a CSS-in-JS library with near-zero runtime, SSR support, and a best-in-class developer experience. It features a first-class variants API for building type-safe, composable component styles. Styles are generated at build time where possible, and it uses atomic CSS output to minimize bundle size. Stitches provides a robust theming system with design tokens and supports responsive variant application. Note: Stitches is currently in maintenance mode but remains widely used in production codebases.

Setup & Configuration

Installation

npm install @stitches/react
# or for core (framework-agnostic)
npm install @stitches/core

Create Stitches Configuration

// stitches.config.ts
import { createStitches } from '@stitches/react'

export const {
  styled,
  css,
  globalCss,
  keyframes,
  getCssText,
  theme,
  createTheme,
  config,
} = createStitches({
  theme: {
    colors: {
      gray100: '#f7fafc',
      gray900: '#1a202c',
      blue500: '#3b82f6',
      blue600: '#2563eb',
      white: '#ffffff',
      text: '$gray900',
      background: '$white',
      primary: '$blue500',
      primaryDark: '$blue600',
    },
    space: {
      1: '4px',
      2: '8px',
      3: '12px',
      4: '16px',
      5: '20px',
      6: '24px',
      8: '32px',
    },
    fontSizes: {
      sm: '0.875rem',
      base: '1rem',
      lg: '1.125rem',
      xl: '1.25rem',
      '2xl': '1.5rem',
    },
    radii: {
      sm: '4px',
      md: '8px',
      lg: '12px',
      full: '9999px',
    },
    shadows: {
      sm: '0 1px 2px rgba(0, 0, 0, 0.05)',
      md: '0 4px 6px rgba(0, 0, 0, 0.1)',
      lg: '0 10px 15px rgba(0, 0, 0, 0.1)',
    },
  },
  media: {
    sm: '(min-width: 640px)',
    md: '(min-width: 768px)',
    lg: '(min-width: 1024px)',
    xl: '(min-width: 1280px)',
    dark: '(prefers-color-scheme: dark)',
  },
  utils: {
    // Margin shorthand
    mx: (value: string) => ({ marginLeft: value, marginRight: value }),
    my: (value: string) => ({ marginTop: value, marginBottom: value }),
    // Padding shorthand
    px: (value: string) => ({ paddingLeft: value, paddingRight: value }),
    py: (value: string) => ({ paddingTop: value, paddingBottom: value }),
    // Size shorthand
    size: (value: string) => ({ width: value, height: value }),
    // Linear gradient
    linearGradient: (value: string) => ({
      backgroundImage: `linear-gradient(${value})`,
    }),
  },
})

Global Styles

// globalStyles.ts
import { globalCss } from './stitches.config'

export const globalStyles = globalCss({
  '*': { margin: 0, padding: 0, boxSizing: 'border-box' },
  body: {
    fontFamily: 'system-ui, -apple-system, sans-serif',
    color: '$text',
    backgroundColor: '$background',
  },
  a: { color: 'inherit', textDecoration: 'none' },
})

// Call in App root:
// globalStyles()

SSR Setup (Next.js)

// pages/_document.tsx
import { getCssText } from '../stitches.config'
import { Html, Head, Main, NextScript } from 'next/document'

export default function Document() {
  return (
    <Html>
      <Head>
        <style id="stitches" dangerouslySetInnerHTML={{ __html: getCssText() }} />
      </Head>
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}

Core Patterns

Styled Components with Variants

import { styled } from '../stitches.config'

const Button = styled('button', {
  // Base styles
  fontFamily: 'inherit',
  border: 'none',
  cursor: 'pointer',
  display: 'inline-flex',
  alignItems: 'center',
  justifyContent: 'center',
  fontWeight: 600,
  transition: 'all 150ms ease',

  // Variants
  variants: {
    size: {
      sm: { fontSize: '$sm', px: '$3', py: '$1', borderRadius: '$sm' },
      md: { fontSize: '$base', px: '$4', py: '$2', borderRadius: '$md' },
      lg: { fontSize: '$lg', px: '$6', py: '$3', borderRadius: '$md' },
    },
    color: {
      primary: {
        backgroundColor: '$primary',
        color: '$white',
        '&:hover': { backgroundColor: '$primaryDark' },
      },
      outline: {
        backgroundColor: 'transparent',
        border: '2px solid $primary',
        color: '$primary',
        '&:hover': { backgroundColor: '$primary', color: '$white' },
      },
      ghost: {
        backgroundColor: 'transparent',
        color: '$primary',
        '&:hover': { backgroundColor: '$gray100' },
      },
    },
    fullWidth: {
      true: { width: '100%' },
    },
  },

  // Compound variants
  compoundVariants: [
    {
      color: 'outline',
      size: 'lg',
      css: { borderWidth: '3px' },
    },
  ],

  // Default variants
  defaultVariants: {
    size: 'md',
    color: 'primary',
  },
})

// Usage — fully type-safe
<Button size="lg" color="outline">Click Me</Button>
<Button fullWidth>Submit</Button>

Theming

import { createTheme } from '../stitches.config'

const darkTheme = createTheme({
  colors: {
    text: '#f7fafc',
    background: '#1a202c',
    gray100: '#2d3748',
    primary: '#63b3ed',
    primaryDark: '#4299e1',
  },
})

// Apply theme class to a container or <body>
<div className={darkTheme}>
  <App />
</div>

Responsive Variants

const Grid = styled('div', {
  display: 'grid',
  gap: '$4',
  variants: {
    columns: {
      1: { gridTemplateColumns: '1fr' },
      2: { gridTemplateColumns: 'repeat(2, 1fr)' },
      3: { gridTemplateColumns: 'repeat(3, 1fr)' },
    },
  },
  defaultVariants: {
    columns: 1,
  },
})

// Apply different variants at different breakpoints
<Grid columns={{ '@initial': 1, '@sm': 2, '@lg': 3 }}>
  <Card />
  <Card />
  <Card />
</Grid>

Polymorphic Components

const Text = styled('span', {
  variants: {
    size: {
      body: { fontSize: '$base', lineHeight: 1.6 },
      heading: { fontSize: '$2xl', fontWeight: 700, lineHeight: 1.2 },
      caption: { fontSize: '$sm', color: '$gray900' },
    },
  },
})

// Render as different HTML elements
<Text as="h1" size="heading">Page Title</Text>
<Text as="p" size="body">Paragraph content</Text>
<Text as="label" size="caption">Field label</Text>

Composing and Overriding Styles

const BaseCard = styled('div', {
  padding: '$4',
  borderRadius: '$lg',
  boxShadow: '$md',
  backgroundColor: '$white',
})

const InteractiveCard = styled(BaseCard, {
  cursor: 'pointer',
  transition: 'transform 200ms ease, box-shadow 200ms ease',
  '&:hover': {
    transform: 'translateY(-2px)',
    boxShadow: '$lg',
  },
})

// One-off overrides with css prop
<BaseCard css={{ border: '1px solid $gray100', maxWidth: '400px' }}>
  Content
</BaseCard>

Best Practices

  • Define all design tokens (colors, spacing, font sizes) in the Stitches config rather than using raw values in styled components, ensuring consistency and easy theme switching.
  • Use the variants API instead of conditional style props — it produces type-safe, statically extractable styles and avoids runtime style recalculation.
  • Leverage compound variants for style combinations that cannot be expressed as independent variant axes, keeping component APIs clean.

Common Pitfalls

  • Using the css prop excessively for one-off overrides defeats the purpose of atomic CSS generation and can lead to style bloat. Prefer defining variants for recurring patterns.
  • Forgetting to call getCssText() in SSR setups causes a flash of unstyled content on first page load, because styles are only injected client-side by default.

Anti-Patterns

Using the service without understanding its pricing model. Cloud services bill differently — per request, per GB, per seat. Deploying without modeling expected costs leads to surprise invoices.

Hardcoding configuration instead of using environment variables. API keys, endpoints, and feature flags change between environments. Hardcoded values break deployments and leak secrets.

Ignoring the service's rate limits and quotas. Every external API has throughput limits. Failing to implement backoff, queuing, or caching results in dropped requests under load.

Treating the service as always available. External services go down. Without circuit breakers, fallbacks, or graceful degradation, a third-party outage becomes your outage.

Coupling your architecture to a single provider's API. Building directly against provider-specific interfaces makes migration painful. Wrap external services in thin adapter layers.

Install this skill directly: skilldb add css-styling-services-skills

Get CLI access →