Zero-runtime Stylesheets-in-TypeScript
@vanilla-extract/css is a build-time CSS-in-TypeScript library that generates static CSS files from TypeScript style definitions. Unlike runtime CSS-in-JS solutions, it compiles styles during the build process, producing plain CSS that ships to the browser with zero JavaScript overhead. This approach combines the developer experience benefits of CSS-in-JS (type safety, code colocation, variables) with the performance characteristics of traditional CSS.
The library requires a bundler integration (Webpack, Vite, esbuild) that processes special .css.ts files. These files export style objects using the package's API, and the bundler plugin transforms them into CSS files with locally scoped class names. The generated class names are stable and deterministic, making them suitable for server-side rendering and static site generation.
With over 1.3 million weekly downloads, @vanilla-extract/css has been adopted by teams building design systems and performance-critical applications. It's framework-agnostic and works with React, Vue, Svelte, or vanilla JavaScript. The library excels in scenarios where you need CSS Modules-like scoping but want TypeScript integration, theme management, and the ability to compute styles based on build-time constants.
The type safety extends beyond basic CSS properties. The package uses CSSType for full CSS property validation, catches typos at compile time, and provides autocomplete for all CSS values. Themes are type-safe contracts that prevent mismatched variable usage across different theme implementations, making it particularly valuable for large codebases with multiple contributors.
import { createTheme, style, styleVariants, globalStyle } from '@vanilla-extract/css';
// Define a theme contract
export const [themeClass, vars] = createTheme({
color: {
primary: '#3b82f6',
background: '#ffffff',
text: '#1f2937'
},
space: {
small: '8px',
medium: '16px',
large: '24px'
}
});
// Create a dark theme using the same contract
export const darkThemeClass = createTheme(vars, {
color: {
primary: '#60a5fa',
background: '#1f2937',
text: '#f9fafb'
},
space: {
small: '8px',
medium: '16px',
large: '24px'
}
});
// Define a base button style
export const button = style({
padding: `${vars.space.small} ${vars.space.medium}`,
backgroundColor: vars.color.primary,
color: vars.color.background,
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '16px',
':hover': {
opacity: 0.9
}
});
// Create button variants
export const buttonVariants = styleVariants({
small: { fontSize: '14px', padding: vars.space.small },
large: { fontSize: '18px', padding: vars.space.large }
});
// Usage in a component:
// import { themeClass, button, buttonVariants } from './styles.css';
// <div className={themeClass}>
// <button className={`${button} ${buttonVariants.large}`}>Click me</button>
// </div>Component Libraries and Design Systems: Create reusable components with strongly-typed theme tokens that enforce consistent spacing, colors, and typography across an entire organization. The theme contract system ensures all theme implementations provide the same variables, preventing runtime errors.
Performance-Critical Applications: Build web applications where runtime performance is paramount, such as e-commerce sites or content platforms. Since styles are pre-compiled to static CSS, there's no client-side style injection overhead, improving Time to Interactive and First Contentful Paint metrics.
Server-Side Rendered Applications: Implement SSR or static site generation with reliable CSS delivery. The deterministic class name generation ensures styles match between server and client, avoiding hydration mismatches that plague runtime CSS-in-JS solutions.
Multi-Theme Applications: Create products that support light/dark modes or white-labeling with multiple simultaneous themes. The scoped theme system allows different parts of the application to use different themes without global CSS variable conflicts.
Type-Safe Responsive Design: Define responsive breakpoints and spacing scales as typed constants that can be referenced across your styles. The TypeScript integration catches errors when using non-existent breakpoints or theme values during development rather than in production.
npm install @vanilla-extract/csspnpm add @vanilla-extract/cssbun add @vanilla-extract/css