Polymorphic, usage-driven CSS-in-JS.
Warning: Boss CSS is not production-ready yet. Expect breaking changes and stability issues.
Website | Documentation | Learn More
- Why Boss CSS
- Choose a Setup
- Quick Start
- What It Looks Like
- Usage Examples
- Solution Patterns
- How It Works
- Strategy Modes
- Compile
- CSS Boundaries
- AI Ready
- Plugin Surface
- Where It Shines
- Docs Map
- Status
- License
Boss CSS is a styling engine with two authoring inputs, multiple output strategies, and an optional compile step.
Think about it in three layers:
- Authoring inputs
$$JSX props- static
className/classsyntax
- Output strategies
inline-firstclassname-firstclassname-onlyruntime
- Build modes
- PostCSS /
build/watch - optional
compile
- PostCSS /
The project is built around a plugin pipeline:
parserplugins extract style intent from source files.propplugins handle CSS props, pseudos, media queries, child selectors, and Bosswind aliases.useplugins add cross-cutting features such as tokens.strategyplugins choose how output is emitted.
Core capabilities:
- Polymorphic
$$authoring with generated framework runtime adapters. - JSX props and static className parsing in the same engine.
- Generated TypeScript types for CSS props and prepared components.
- Token support, pseudo selectors, breakpoints, and arbitrary child selectors.
- Multiple output strategies, plus optional compile-time source rewriting.
- Bosswind for Tailwind-like prop aliases on top of the same engine.
- CLI and PostCSS integration for build, watch, compile, and dev workflows.
- Framework and bundler agnostic.
Important distinctions:
generated runtimemeans.bo$$/index.jsand.bo$$/index.d.ts.runtimeis the runtime strategy plugin for runtime-only or hybrid browser evaluation.compileis a build step, not a strategy.
| You want to author with | Pick this strategy | Import near app root | When to choose it |
|---|---|---|---|
$$ JSX props with the default output |
inline-first |
import './.bo$$' |
Small CSS output, recommended starting point |
$$ JSX props with more static class rules |
classname-first |
import './.bo$$' |
Cacheable class-heavy CSS, dynamic values as functions. Closest eqvivalent to Tailwind. |
Static className / class tokens only |
classname-only |
import './.bo$$/styles.css' |
Static class string lane, no generated runtime files |
$$ JSX props with browser-evaluated values or no server CSS |
runtime |
import './.bo$$' |
Runtime-only or hybrid behavior |
boss-css compile comes after this choice. It follows inline-first or classname-first; it does not replace them.
Scaffold the config, runtime, and starter files:
npx boss-css initImport the generated runtime once near your app root:
import './.bo$$'If you choose classname-only, import ./.bo$$/styles.css only instead.
Typical commands after setup:
npx boss-css build
npx boss-css watch
npx boss-css devIf you want to wire it up manually, start with the docs:
- Quick start: https://bosscss.com/docs/getting-started/quick-start
- Configuration: https://bosscss.com/docs/getting-started/configuration
- Runtime strategy: https://bosscss.com/docs/concepts/runtime-strategy
Boss CSS using component props is designed for React, Next.js, Preact, Solid, Qwik, and Stencil projects. There is also a React Native flow in the docs.
export function Hero() {
return (
<$$
display="grid"
gap={16}
padding={[20, 24]}
borderRadius={18}
backgroundColor="#111c31"
color="#f5f8ff"
hover={{ backgroundColor: '#15233d' }}
at={{ 'mobile+': { gap: 20, padding: [24, 28] } }}
>
Boss CSS
</$$>
)
}JSX props
export function SurfaceCard() {
return (
<$$
display="flex"
alignItems="center"
gap={12}
padding={12}
borderRadius={18}
backgroundColor="#111c31"
color="#f5f8ff"
>
Surface card
</$$>
)
}className syntax
export function SurfaceCard() {
return (
<div className="display:flex align-items:center gap:12 padding:12 border-radius:18 background-color:#111c31 color:#f5f8ff">
Surface card
</div>
)
}Bosswind + JSX props
export function SurfaceCard() {
return (
<$$ flex items="center" gap={4} p={4} rounded="xl" backgroundColor="#111c31" color="#f5f8ff">
Surface card
</$$>
)
}Bosswind + className
export function SurfaceCard() {
return (
<div className="flex items:center gap:4 p:4 rounded:xl background-color:#111c31 color:#f5f8ff">
Surface card
</div>
)
}JSX props
export function ActionButton() {
return (
<$$
display="inline-flex"
alignItems="center"
justifyContent="center"
gap={6}
padding={[9, 12]}
borderRadius={999}
backgroundColor="#111"
color="#fff"
hover={{ backgroundColor: '#222' }}
>
Save
</$$>
)
}className syntax
export function ActionButton() {
return (
<button className="display:inline-flex align-items:center justify-content:center gap:6 padding:9_12 border-radius:999 background-color:#111 color:#fff hover:background-color:#222">
Save
</button>
)
}Bosswind + JSX props
export function ActionButton() {
return (
<$$
inlineFlex
items="center"
justify="center"
gap={2}
py={3}
px={4}
rounded="full"
bg="#111"
color="#fff"
hover={{ bg: '#222' }}
>
Save
</$$>
)
}Bosswind + className
export function ActionButton() {
return (
<button className="inline-flex items:center justify:center gap:2 py:3 px:4 rounded:full bg:#111 color:#fff hover:bg:#222">
Save
</button>
)
}export function CTA() {
return (
<$$
color="#111"
backgroundColor="#fff"
hover={{
color: '#fff',
backgroundColor: '#111',
}}
focus={{
outline: '2px solid #6dd6ff',
outlineOffset: 2,
}}
at={{
'mobile+': {
padding: [14, 18],
fontSize: 18,
},
}}
>
Press
</$$>
)
}export function CardList() {
return (
<$$
display="grid"
gap={12}
child={{
'.title': { fontWeight: 700 },
'.meta': { opacity: 0.65 },
'&>article': { padding: 16, borderRadius: 16, backgroundColor: '#111c31' },
}}
>
<article>
<div className="title">Card title</div>
<div className="meta">Meta copy</div>
</article>
</$$>
)
}export function Badge() {
return (
<span className="display:inline-flex align-items:center gap:6 padding:6_10 border-radius:999 background-color:#111 color:#fff">
New
</span>
)
}Grouped pseudo/media syntax is also supported:
<button className="mobile:hover:{background-color:black;color:white} focus-visible:{outline:2_solid;outline-color:#6dd6ff}">
Hover me
</button><div className="[&_.title]:font-weight:700 [.title_&]:color:red">
<span className="title">Title</span>
</div><$$ margin={[20, 0]} padding={[8, 16]} />
<div
className="
display:flex
gap:12
hover:color:red
focus-visible:background-color:black
"
/>export function Mixed({ tone }: { tone: 'light' | 'dark' }) {
return (
<$$
className="display:flex align-items:center gap:12 border-radius:14 padding:12_16"
color={tone === 'dark' ? '#fff' : '#111'}
/>
)
}export function ThemedPanel() {
return (
<$$
tokens={{
color: {
brand: '#8b5cf6',
background: '#0b1220',
},
}}
backgroundColor="background"
color="brand"
padding={20}
borderRadius={18}
>
Local theme override
</$$>
)
}const surface = $$.$({
display: 'flex',
gap: 12,
padding: 16,
borderRadius: 16,
hover: { color: 'purple' },
})
export function PlainDiv() {
return <div {...$$.style(surface)} />
}import { cv } from 'boss-css/variants'
const button = cv({
base: 'display:inline-flex align-items:center justify-content:center gap:8 padding:10_14 border-radius:999',
variants: {
tone: {
primary: 'background-color:black color:white',
subtle: 'background-color:transparent color:black border:1_solid border-color:black',
},
},
defaultVariants: {
tone: 'primary',
},
})
button({ tone: 'subtle' })Access utilities directly on the global $$ proxy:
const className = $$.cx('display:flex gap:12', isActive && 'color:blue', isMuted && 'opacity:0.6')$$.Card = $$.$({
padding: 18,
borderRadius: 18,
backgroundColor: '#111c31',
color: '#f5f8ff',
hover: { backgroundColor: '#15233d' },
})
export function Demo() {
return <$$.Card>Prepared component</$$.Card>
}Enable the Bosswind plugin when you want Tailwind-style aliases and tokens:
export function BosswindCard() {
return (
<$$ flex items="center" gapX={4} p={4} rounded="xl" bg="blue.600" hover={{ bg: 'blue.700' }}>
Bosswind
</$$>
)
}$$.Stack = $$.$({
display: 'flex',
flexDirection: 'column',
gap: 12,
})
export function DialogSection() {
return (
<$$.Stack gap={16} padding={20}>
<h2>Dialog title</h2>
<p>Content</p>
</$$.Stack>
)
}JSX props
export function ToolbarRow() {
return (
<$$
display="flex"
alignItems="center"
justifyContent="space-between"
gap={12}
padding={12}
borderRadius={18}
backgroundColor="#111c31"
color="#fff"
>
<span>Title</span>
<span>Status</span>
</$$>
)
}className syntax
export function ToolbarRow() {
return (
<div className="display:flex align-items:center justify-content:space-between gap:12 padding:12 border-radius:18 background-color:#111c31 color:#fff">
<span>Title</span>
<span>Status</span>
</div>
)
}Bosswind + JSX props
export function ToolbarRow() {
return (
<$$ flex items="center" justify="between" gap={4} p={4} rounded="xl" bg="#111c31" color="#fff">
<span>Title</span>
<span>Status</span>
</$$>
)
}Bosswind + className
export function ToolbarRow() {
return (
<div className="flex items:center justify:between gap:4 p:4 rounded:xl bg:#111c31 color:#fff">
<span>Title</span>
<span>Status</span>
</div>
)
}export function MarketingSection({ dark }: { dark: boolean }) {
return (
<$$
tokens={{
color: dark ? { text: '#f8fafc', panel: '#0f172a' } : { text: '#0f172a', panel: '#ffffff' },
}}
backgroundColor="panel"
color="text"
padding={[24, 28]}
borderRadius={20}
>
Themeable content
</$$>
)
}JSX props
export function DashboardShell() {
return (
<$$ display="grid" gap={12}>
<$$
display="flex"
alignItems="center"
justifyContent="space-between"
padding={12}
borderRadius={18}
backgroundColor="#111c31"
color="#fff"
>
Header
</$$>
<$$ display="grid" gap={12}>
<$$ padding={12} borderRadius={12} backgroundColor="#eef2ff">
Card A
</$$>
<$$ padding={12} borderRadius={12} backgroundColor="#eef2ff">
Card B
</$$>
</$$>
</$$>
)
}className syntax
export function DashboardShell() {
return (
<div className="display:grid gap:12">
<div className="display:flex align-items:center justify-content:space-between padding:12 border-radius:18 background-color:#111c31 color:#fff">
Header
</div>
<div className="display:grid gap:12">
<div className="padding:12 border-radius:12 background-color:#eef2ff">Card A</div>
<div className="padding:12 border-radius:12 background-color:#eef2ff">Card B</div>
</div>
</div>
)
}Bosswind + JSX props
export function DashboardShell() {
return (
<$$ grid gap={4}>
<$$ flex items="center" justify="between" p={4} rounded="xl" bg="#111c31" color="#fff">
Header
</$$>
<$$ grid gap={4}>
<$$ p={4} rounded="lg" bg="#eef2ff">
Card A
</$$>
<$$ p={4} rounded="lg" bg="#eef2ff">
Card B
</$$>
</$$>
</$$>
)
}Bosswind + className
export function DashboardShell() {
return (
<div className="grid gap:4">
<div className="flex items:center justify:between p:4 rounded:xl bg:#111c31 color:#fff">Header</div>
<div className="grid gap:4">
<div className="p:4 rounded:lg bg:#eef2ff">Card A</div>
<div className="p:4 rounded:lg bg:#eef2ff">Card B</div>
</div>
</div>
)
}Boss CSS is usage-driven. The source code you write determines what CSS and generated runtime files Boss emits.
High-level flow:
- Parse source files from
$$JSX and/or static className strings. - Convert that input into a normalized prop tree.
- Run the tree through prop plugins such as
css,pseudo,at,child,bosswind, andtoken. - Let the selected strategy decide what becomes CSS, inline styles, variables, or browser-evaluated work.
- Emit generated runtime files when the chosen strategy needs them, plus d.ts files and CSS.
The same engine can produce very different outputs, but the choices are not completely interchangeable:
inline-firstoutput for minimal CSS,classname-firstfor more class-oriented output,classname-onlyfor static className builds,runtimefor runtime-only or hybrid browser evaluation.
Important constraints:
classname-onlyis the static className lane. It is not the whole no-generated-runtime story.runtime.onlydisables static className parsing.compilecurrently supports JSX withinline-firstandclassname-firstonly.
Boss CSS supports four output strategies:
inline-first: Default. Pushes as much as possible into inline styles or CSS variables and keeps stylesheet output small.classname-first: Prefers classes where possible and uses runtime logic for dynamic values.classname-only: CSS-only static className parsing with no generated JSX runtime files.runtime: Runtime strategy wrapper for runtime-only or hybrid mode when values must be resolved in the browser.
Read more: https://bosscss.com/docs/concepts/runtime-strategy
Each strategy changes four things:
- what you author,
- which generated files exist,
- what lands in CSS,
- what still runs in the browser.
Those differences matter more than the slogan version of “runtime”:
inline-first: minimal CSS, small generated runtime
This is the default strategy for $$ JSX. Top-level props lean inline. Nested selectors like hover, at, and child
become CSS rules with variables.
Config:
import * as jsx from 'boss-css/parser/jsx/server'
import * as css from 'boss-css/prop/css/server'
import * as pseudo from 'boss-css/prop/pseudo/server'
import * as inlineFirst from 'boss-css/strategy/inline-first/server'
export default {
plugins: [css, pseudo, jsx, inlineFirst],
}You write:
<$$
display="inline-flex"
alignItems="center"
gap={8}
padding={[8, 10]}
borderRadius={12}
backgroundColor="#111c31"
color="white"
hover={{ backgroundColor: '#15233d' }}
>
Save
</$$>Boss emits:
.bo$$/index.jsand.bo$$/index.d.tsfor the generated JSX runtime helpers- a small
.bo$$/styles.cssfile mostly for nested selectors - base props that tend to stay inline, while
hover,at, andchildrules become CSS
Typical emitted output:
<div
className="hover:background-color"
style={{
display: 'inline-flex',
alignItems: 'center',
gap: '8px',
padding: '8px 12px',
borderRadius: '12px',
backgroundColor: '#111c31',
color: 'white',
'--hover-background-color': '#15233d',
}}
>
Save
</div>What lands in .bo$$/styles.css:
.hover\:background-color:hover {
background-color: var(--hover-background-color);
}Base props like display, gap, padding, and backgroundColor stay inline here, so they do not produce class rules.
classname-first: load once, reuse classes
This keeps the same $$ authoring style, but static values prefer generated classnames instead of inline styles.
Dynamic values need to be functions so the runtime can decide which values need to use static classes versus CSS
variables.
Config:
import * as jsx from 'boss-css/parser/jsx/server'
import * as css from 'boss-css/prop/css/server'
import * as pseudo from 'boss-css/prop/pseudo/server'
import * as classnameFirst from 'boss-css/strategy/classname-first/server'
export default {
plugins: [css, pseudo, jsx, classnameFirst],
}You write:
<$$
display="inline-flex"
alignItems="center"
gap={8}
padding={[8, 12]}
borderRadius={12}
backgroundColor="#111c31"
color="white"
hover={{ backgroundColor: '#15233d' }}
>
Save
</$$>Boss emits:
.bo$$/index.js,.bo$$/index.d.ts, and.bo$$/styles.css- class-oriented output for static values, closer to utility-style CSS, eg. Tailwind
- runtime handling only where values are truly dynamic, usually as function props like
backgroundColor={() => tone}
Typical emitted output:
<div className="display:inline-flex align-items:center gap:8 padding:8_12 border-radius:12 background-color:#111c31 color:white hover:background-color:#15233d">
Save
</div>What lands in .bo$$/styles.css:
.display\:inline-flex {
display: inline-flex;
}
.align-items\:center {
align-items: center;
}
.gap\:8 {
gap: 8px;
}
.padding\:8px_12px {
padding: 8px 12px;
}
.border-radius\:12 {
border-radius: 12px;
}
.background-color\:\#111c31 {
background-color: #111c31;
}
.color\:white {
color: white;
}
.hover\:background-color\:\#15233d:hover {
background-color: #15233d;
}classname-only: CSS only from static className syntax
This is the CSS-only strategy for static className authoring. It parses static className strings, emits CSS, and skips
the generated JSX runtime entirely.
Config:
import * as classname from 'boss-css/parser/classname/server'
import * as css from 'boss-css/prop/css/server'
import * as pseudo from 'boss-css/prop/pseudo/server'
import * as classnameOnly from 'boss-css/strategy/classname-only/server'
export default {
plugins: [css, pseudo, classname, classnameOnly],
}You write:
<button className="display:inline-flex align-items:center gap:8 padding:8px_12px border-radius:12 background-color:#111c31 color:white hover:background-color:#15233d">
Save
</button>Boss emits:
.bo$$/styles.css- no
.bo$$/index.js - no
.bo$$/index.d.ts - no JSX runtime work in the browser
- import
.bo$$/styles.cssmanually
Typical output:
.display\:inline-flex {
display: inline-flex;
}
.align-items\:center {
align-items: center;
}
.gap\:8 {
gap: 8px;
}
.padding\:8px_12px {
padding: 8px 12px;
}
.border-radius\:12 {
border-radius: 12px;
}
.background-color\:\#111c31 {
background-color: #111c31;
}
.color\:white {
color: white;
}
.hover\:background-color\:\#15233d:hover {
background-color: #15233d;
}Use this when your styles are static and you want the smallest possible client footprint.
runtime: runtime strategy for browser-resolved values
Use this when values must be computed in the browser. The runtime strategy wraps inline-first, classname-first, or
classic, and can run fully client-side or alongside server output.
Config:
import * as jsx from 'boss-css/parser/jsx/server'
import * as css from 'boss-css/prop/css/server'
import * as pseudo from 'boss-css/prop/pseudo/server'
import * as runtime from 'boss-css/strategy/runtime/server'
export default {
plugins: [css, pseudo, jsx, runtime],
runtime: {
only: true,
strategy: 'inline-first',
},
}You write:
<$$
display="inline-flex"
alignItems="center"
gap={8}
padding="8px 12px"
borderRadius={12}
backgroundColor={() => tone}
color="white"
hover={{ backgroundColor: () => hoverTone }}
>
Save
</$$>Boss emits:
.bo$$/index.jsand.bo$$/index.d.tsfor the generated runtime- no server CSS in
runtime.only: truemode unless you chooseruntime.globals: 'file' - runtime style injection in the browser based on the selected strategy
- hybrid mode when
runtime.only: false, which keeps server CSS output and still evaluates dynamic props - static
classNameparsing is disabled inruntime.onlymode
Typical browser output when runtime.strategy is inline-first:
<div
className="hover:background-color"
style={{
display: 'inline-flex',
alignItems: 'center',
gap: '8px',
padding: '8px 12px',
borderRadius: '12px',
backgroundColor: tone,
color: 'white',
'--hover-background-color': hoverTone,
}}
>
Save
</div>What lands in .bo$$/styles.css:
runtime.only: true: no strategy CSS file. Rules are injected by the runtime in the browser. Ifruntime.globals: 'file', the file only contains global CSS such as reset, fontsource, and$$.css(...).runtime.only: false: the file contains the same strategy CSS you would get without runtime-only. Forruntime.strategy: 'inline-first', that means:
.hover\:background-color:hover {
background-color: var(--hover-background-color);
}boss-css compile is an optional build step. It is not a strategy.
It follows your configured inline-first or classname-first strategy and rewrites supported JSX into plain elements,
folds Boss markers into normal DOM props, optimizes classNames, and removes Boss runtime imports when they are no longer
needed.
Today, compile supports inline-first and classname-first.
In temp mode, compile mirrors transformed source and generated CSS under compile.tempOutDir. In prod mode it mutates
source in place and does not write CSS files.
Compile is bundler agnostic by design (no Babel, Webpack, Vite, etc. plugins). It is meant to run during CI before your
own build step, so ideally you do lint => boss compile => build.
Compile example: static $$ becomes a plain element
Input:
export const Example = () => <$$ className="card" display="block" hover={{ color: 'red' }} />Output:
export const Example = () => <div className="card hover:color" style={{ display: 'block', '--hover-color': 'red' }} />CSS:
.hover\:color:hover {
color: var(--hover-color);
}Boss can split CSS output by folder boundaries instead of pushing everything into a single stylesheet.
Example layout:
src/
app/
app.boss.css
layout.tsx
admin/
admin.boss.css
layout.tsx
marketing/
marketing.boss.css
layout.tsx
Import each boundary where that section of the app starts:
// src/app/layout.tsx
import './app.boss.css'
// src/app/admin/layout.tsx
import './admin.boss.css'
// src/marketing/layout.tsx
import './marketing.boss.css'How it behaves:
- Keep the boundary files empty.
- Rules used by only one section stay in that section's
*.boss.css. - Shared rules are hoisted to the nearest common ancestor boundary or
.bo$$/styles.css. - This is useful when app, admin, marketing, docs, or embedded surfaces should load different CSS bundles.
Read more: https://bosscss.com/docs/recipes/css-boundaries-layout
Boss can generate live project context for coding agents, not just CSS and runtime files.
The AI plugin writes:
.bo$$/LLMS.md: a live markdown reference with tokens, pseudos, breakpoints, strategies, boundaries, prepared components, and other generated metadata.bo$$/skills/: agent skills, each with its ownSKILL.md
Minimal setup:
import * as ai from 'boss-css/ai/server'
export default {
plugins: [
ai,
// ...other plugins
],
}What makes it useful:
boss-css initenables it by default- place
aiearly if other plugins emit metadata duringonBoot - build, watch, PostCSS, and compile sessions keep the files updated
- plugins can publish extra agent context through
onMetaData - generated skills can be installed into agents directly
npx skills add "./.bo$$/skills" -a codex -a claude-codeIf you want Boss-aware agents in a repo, this is the bridge between your live config/output and the agent prompt.
Read more: https://bosscss.com/docs/tooling/ai
The built-in plugin set is intentionally modular.
Common plugins:
boss-css/parser/jsx/serverboss-css/parser/classname/serverboss-css/prop/css/serverboss-css/prop/pseudo/serverboss-css/prop/at/serverboss-css/prop/child/serverboss-css/prop/bosswind/serverboss-css/use/token/serverboss-css/strategy/inline-first/serverboss-css/strategy/classname-first/serverboss-css/strategy/classname-only/serverboss-css/strategy/runtime/server
There are matching browser and runtime-only modules where needed.
This makes Boss CSS good at two things:
- staying small when you only want a subset of features,
- staying extensible when you want custom prop plugins or custom non-CSS props.
If you want ideas for where Boss CSS feels strongest, start here:
- Build a typed design-system layer where primitives stay close to real CSS props.
- Migrate a utility-heavy codebase toward JSX props without abandoning className parsing.
- Keep Boss browser work minimal for mostly static applications.
- Use runtime-only or hybrid mode for dashboards, editors, or theme-heavy apps with dynamic values.
- Create prepared components that feel like styled primitives without hiding the underlying prop model.
- Add a custom prop plugin for product-specific shorthands instead of encoding them in component props.
- Use Bosswind when you want Tailwind-like aliases but still want the same parser, token, and strategy system.
Useful entry points:
- Quick start: https://bosscss.com/docs/getting-started/quick-start
- Configuration: https://bosscss.com/docs/getting-started/configuration
- JSX usage: https://bosscss.com/docs/usage/jsx
- ClassName syntax: https://bosscss.com/docs/usage/classname
- Tokens and theming: https://bosscss.com/docs/usage/tokens
- Bosswind: https://bosscss.com/docs/usage/bosswind
- Compile: https://bosscss.com/docs/tooling/compile
- CSS boundaries: https://bosscss.com/docs/recipes/css-boundaries-layout
- AI plugin: https://bosscss.com/docs/tooling/ai
- Prepared components: https://bosscss.com/docs/usage/prepared-components
- Composition and variants: https://bosscss.com/docs/recipes/composition-and-variants
- Runtime-only mode: https://bosscss.com/docs/recipes/runtime-only
- Custom plugins: https://bosscss.com/docs/recipes/custom-plugin
Boss CSS is still early.
Current expectations:
- APIs can change.
- Edge cases still exist in parsing and runtime behavior.
- Documentation is ahead of production hardening in some areas.
- It is better suited to experimentation, internal tools, and early adopters than broad production rollout today.
MIT
