A lightweight compile-time CSS-in-JS library for React apps
Features • Quick Start • Setup • Usage • API • Ecosystem
- ⚡ True Zero Runtime: styles are extracted at compile-time, no JS in production
- 💎 Native CSS: write regular CSS with all modern features
- 📦 Modern Bundlers: built-in support for Next.js (Turbopack) and Vite (Rolldown)
- 🔥 Hot Reload: instant CSS updates during development
- 🌐 Global Types: eliminate the need to import
cssin every module - 🧩 VS Code Extension: syntax highlighting, validation, autocompletion, tooltips, and more
- 🧹 ESLint Plugin: auto-fixable formatting rules for CSS inside templates
No need to read further, just try it out:
pnpm create rawstyle # scaffold a demo project for your chosen platform- Install the сore and the appropriate bundler plugin:
pnpm add -D rawstyle @rawstyle/next # for Next.js
pnpm add -D rawstyle @rawstyle/vite # for Vite- Configure the bundler to use the plugin:
// next.config.ts
import { rawstyleTurboRule } from '@rawstyle/next'
import type { NextConfig } from 'next'
export default {
turbopack: { rules: { ...rawstyleTurboRule } },
} satisfies NextConfigThe loader extracts CSS and injects it into the module as a base64-encoded CSS import.
// vite.config.ts
import react from '@vitejs/plugin-react'
import rawstyle from '@rawstyle/vite'
import type { UserConfig } from 'rolldown-vite'
export default {
plugins: [react(), rawstyle()],
} satisfies UserConfigThe plugin emits a virtual
.cssmodule containing extracted styles and imports it as a side effect.
import { css, gcss, cn } from 'rawstyle'You can make the css, gcss, and cn type declarations global to avoid importing them in every module:
// or add this to your global.d.ts:
import 'rawstyle/globals'
// or
/// <reference types="rawstyle/globals" />Rawstyle provides three core primitives: css, gcss, and cn:
// src/module.tsx
export const Component = ({ theme }: { theme: string }) => (
// cn - class names merging utility
<div className={cn('common', theme === 'dark' && card)}>
Hello, World!
</div>
)
// css - define scoped CSS
const card = css`
padding: 1rem;
color: var(--primary);
&:hover { box-shadow: 0 4px 12px black; }
`
// gcss - define global CSS
void gcss`
:root { --primary: #303030; }
body { margin: 0; background: #ebebeb; }
`This code compiles to:
import '\0virtual.css'
export const Component = ({ theme }: { theme: string }) => (
<div className={['common', theme === 'dark' && 'card_hash5'].filter(Boolean).join(' ')}>
Hello, World!
</div>
)As you can see, the card variable is replaced with a hashed class name, cn is transformed into a conditional string joiner, and the CSS is extracted into a separate virtual .css file:
/* virtual.css */
:root { --primary: #303030; }
body { margin: 0; background: #ebebeb; }
.card_hash5 {
padding: 1rem;
color: var(--primary);
&:hover { box-shadow: 0 4px 12px black; }
}Rawstyle provides a suite of tools to enhance your development experience: