Top Related Projects
Documentation about css-modules
Visual primitives for the component age. Use the best bits of ES6 and CSS to style your apps without stress 💅
👩🎤 CSS-in-JS library designed for high performance style composition
A utility-first CSS framework for rapid UI development.
Zero-runtime CSS in JS library
Quick Overview
Vanilla Extract is a zero-runtime CSS-in-TypeScript library that generates static CSS files during build time. It provides a type-safe way to author styles using TypeScript, offering features like theming, dynamic sprinkles, and CSS modules, all while maintaining the benefits of traditional CSS.
Pros
- Type-safe CSS authoring with TypeScript
- Zero runtime overhead, as styles are generated at build time
- Supports theming and dynamic styles without sacrificing performance
- Integrates well with existing CSS ecosystems and tooling
Cons
- Requires a build step, which may increase complexity in some projects
- Learning curve for developers used to traditional CSS or other CSS-in-JS solutions
- Limited runtime style manipulation compared to some other CSS-in-JS libraries
- Relatively new project, so the ecosystem and community support are still growing
Code Examples
Creating a simple style:
import { style } from '@vanilla-extract/css';
export const container = style({
padding: '20px',
backgroundColor: '#f0f0f0',
});
Defining a theme:
import { createTheme } from '@vanilla-extract/css';
export const [themeClass, vars] = createTheme({
color: {
primary: '#007bff',
secondary: '#6c757d',
},
font: {
body: 'Arial, sans-serif',
},
});
Using sprinkles for responsive styles:
import { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles';
const responsiveProperties = defineProperties({
conditions: {
mobile: {},
tablet: { '@media': 'screen and (min-width: 768px)' },
desktop: { '@media': 'screen and (min-width: 1024px)' },
},
defaultCondition: 'mobile',
properties: {
display: ['none', 'flex', 'block', 'inline'],
flexDirection: ['row', 'column'],
padding: ['0', '4px', '8px', '16px', '32px'],
},
});
export const sprinkles = createSprinkles(responsiveProperties);
Getting Started
-
Install Vanilla Extract:
npm install @vanilla-extract/css
-
Set up your build tool (e.g., webpack, Vite) with the Vanilla Extract plugin.
-
Create a CSS file with a
.css.ts
extension:// styles.css.ts import { style } from '@vanilla-extract/css'; export const myStyle = style({ color: 'blue', fontSize: '16px', });
-
Use the generated class in your component:
import { myStyle } from './styles.css'; function MyComponent() { return <div className={myStyle}>Hello, Vanilla Extract!</div>; }
Competitor Comparisons
Documentation about css-modules
Pros of CSS Modules
- Simpler setup and integration with existing CSS workflows
- Wider adoption and community support
- Works with any CSS preprocessor (SASS, LESS, etc.)
Cons of CSS Modules
- Limited type safety and static analysis
- Requires additional tooling for full CSS-in-JS capabilities
- Less flexibility in dynamic styling and theme generation
Code Comparison
CSS Modules:
.button {
background-color: blue;
color: white;
}
import styles from './Button.css';
const Button = () => <button className={styles.button}>Click me</button>;
Vanilla Extract:
import { style } from '@vanilla-extract/css';
export const button = style({
backgroundColor: 'blue',
color: 'white'
});
import { button } from './Button.css.ts';
const Button = () => <button className={button}>Click me</button>;
CSS Modules offers a more familiar approach for developers accustomed to traditional CSS, while Vanilla Extract provides stronger typing and a more JavaScript-centric workflow. CSS Modules is easier to adopt in existing projects, but Vanilla Extract offers better performance and more advanced features for complex styling needs.
Visual primitives for the component age. Use the best bits of ES6 and CSS to style your apps without stress 💅
Pros of styled-components
- Dynamic styling with JavaScript: Allows for more complex and conditional styles
- Better developer experience with syntax highlighting and auto-completion
- Automatic critical CSS extraction for improved performance
Cons of styled-components
- Runtime overhead: Styles are generated and injected at runtime
- Larger bundle size due to the library itself and generated styles
- Potential for prop pollution and overuse of the styled API
Code Comparison
styled-components:
const Button = styled.button`
background-color: ${props => props.primary ? 'blue' : 'white'};
color: ${props => props.primary ? 'white' : 'blue'};
padding: 10px 20px;
`;
vanilla-extract:
import { style, styleVariants } from '@vanilla-extract/css';
const baseButton = style({
padding: '10px 20px',
});
export const button = styleVariants({
primary: [baseButton, { backgroundColor: 'blue', color: 'white' }],
secondary: [baseButton, { backgroundColor: 'white', color: 'blue' }],
});
Both libraries offer component-based styling solutions, but vanilla-extract generates styles at build time, resulting in zero runtime cost and type-safe CSS. styled-components provides a more familiar CSS-in-JS experience with dynamic styling capabilities at the cost of runtime performance.
👩🎤 CSS-in-JS library designed for high performance style composition
Pros of emotion
- Runtime CSS-in-JS allows for dynamic styling based on props and state
- Extensive ecosystem with additional libraries and integrations
- Supports server-side rendering out of the box
Cons of emotion
- Runtime performance overhead due to style injection
- Larger bundle size compared to static CSS solutions
- Potential for style conflicts in global scope
Code Comparison
emotion:
import { css } from '@emotion/react'
const style = css`
color: hotpink;
`
const SomeComponent = ({ children }) => (
<div css={style}>{children}</div>
)
vanilla-extract:
import { style } from '@vanilla-extract/css'
const myStyle = style({
color: 'hotpink'
})
const SomeComponent = ({ children }) => (
<div className={myStyle}>{children}</div>
)
vanilla-extract generates static CSS at build time, resulting in smaller bundle sizes and better runtime performance. It also provides type safety for styles and class names. However, it lacks the dynamic capabilities of emotion and requires additional setup for server-side rendering.
emotion offers more flexibility for runtime styling and has a larger ecosystem, but comes with performance trade-offs and potential style conflicts. The choice between the two depends on project requirements, performance needs, and developer preferences.
A utility-first CSS framework for rapid UI development.
Pros of Tailwind CSS
- Rapid prototyping and development with utility-first approach
- Extensive pre-built classes for common design patterns
- Large community and ecosystem with numerous resources and plugins
Cons of Tailwind CSS
- Steeper learning curve for developers new to utility-first CSS
- Potential for larger HTML files due to multiple class names
- Less type-safe compared to Vanilla Extract's TypeScript integration
Code Comparison
Tailwind CSS:
<div class="bg-blue-500 text-white p-4 rounded-lg shadow-md">
<h3 class="text-xl font-bold mb-2">Hello, Tailwind!</h3>
<p class="text-sm">This is a sample component.</p>
</div>
Vanilla Extract:
import { style } from '@vanilla-extract/css';
const container = style({
backgroundColor: 'blue',
color: 'white',
padding: '1rem',
borderRadius: '0.5rem',
boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)'
});
const heading = style({
fontSize: '1.25rem',
fontWeight: 'bold',
marginBottom: '0.5rem'
});
const paragraph = style({
fontSize: '0.875rem'
});
Zero-runtime CSS in JS library
Pros of Linaria
- Zero runtime CSS-in-JS with no style injection
- Supports dynamic styles with CSS variables
- Works with server-side rendering out of the box
Cons of Linaria
- Requires additional build step and configuration
- Limited TypeScript support compared to Vanilla Extract
- Less robust theming capabilities
Code Comparison
Linaria:
import { css } from '@linaria/core';
const button = css`
background-color: blue;
color: white;
padding: 10px 20px;
`;
Vanilla Extract:
import { style } from '@vanilla-extract/css';
const button = style({
backgroundColor: 'blue',
color: 'white',
padding: '10px 20px'
});
Both Linaria and Vanilla Extract aim to provide zero-runtime CSS-in-JS solutions, but they differ in their approach and features. Linaria uses a more traditional CSS-like syntax with template literals, while Vanilla Extract leverages TypeScript for enhanced type safety and autocompletion.
Linaria offers better support for dynamic styles through CSS variables, making it easier to create responsive designs. However, Vanilla Extract provides more robust theming capabilities and better TypeScript integration, which can lead to improved developer experience and fewer runtime errors.
Ultimately, the choice between these two libraries depends on specific project requirements, team preferences, and the importance of TypeScript support in your development workflow.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
ð§ vanilla-extract
Zero-runtime Stylesheets-in-TypeScript.
Write your styles in TypeScript (or JavaScript) with locally scoped class names and CSS Variables, then generate static CSS files at build time.
Basically, itâs âCSS Modules-in-TypeScriptâ but with scoped CSS Variables + heaps more.
ð¥ All styles generated at build time â just like Sass, Less, etc.
⨠Minimal abstraction over standard CSS.
ð¦ Works with any front-end framework â or even without one.
ð³ Locally scoped class names â just like CSS Modules.
ð Locally scoped CSS Variables, @keyframes
and @font-face
rules.
ð¨ High-level theme system with support for simultaneous themes. No globals!
ð Utils for generating variable-based calc
expressions.
ðª Type-safe styles via CSSType.
ðââï¸ Optional runtime version for development and testing.
ð Optional API for dynamic runtime theming.
ð Check out the documentation site for setup guides, examples and API docs.
ð¥ Try it out for yourself in CodeSandbox.
Write your styles in .css.ts
files.
// styles.css.ts
import { createTheme, style } from '@vanilla-extract/css';
export const [themeClass, vars] = createTheme({
color: {
brand: 'blue'
},
font: {
body: 'arial'
}
});
export const exampleStyle = style({
backgroundColor: vars.color.brand,
fontFamily: vars.font.body,
color: 'white',
padding: 10
});
ð¡ Once you've configured your build tooling, these
.css.ts
files will be evaluated at build time. None of the code in these files will be included in your final bundle. Think of it as using TypeScript as your preprocessor instead of Sass, Less, etc.
Then consume them in your markup.
// app.ts
import { themeClass, exampleStyle } from './styles.css.ts';
document.write(`
<section class="${themeClass}">
<h1 class="${exampleStyle}">Hello world!</h1>
</section>
`);
Want to work at a higher level while maximising style re-use? Check out ð¨ Sprinkles, our official zero-runtime atomic CSS framework, built on top of vanilla-extract.
Thanks
- Nathan Nam Tran for creating css-in-js-loader, which served as the initial starting point for treat, the precursor to this library.
- Stitches for getting us excited about CSS-Variables-in-JS.
- SEEK for giving us the space to do interesting work.
License
MIT.
Top Related Projects
Documentation about css-modules
Visual primitives for the component age. Use the best bits of ES6 and CSS to style your apps without stress 💅
👩🎤 CSS-in-JS library designed for high performance style composition
A utility-first CSS framework for rapid UI development.
Zero-runtime CSS in JS library
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot