Tools
Tools: Boss-CSS: I created another "CSS-in-JS" lib, and here is why!
2026-03-02
0 views
admin
History ## My relationship with Tailwind ## Boss was born ## Boss CSS ## It's just CSS ## Multiple syntax support ## Prop based styling ## Class name based styling ## Object based styling ## Prepared components ## Raw CSS ## Bosswind ## Runtime?! ## Extraction strategies ## Inline first ## Class name first ## Fully runtime ## Zero runtime extraction ## Framework-agnostic approach ## Goodies ## $$ is global ## Powerful plugin system ## CLI tools ## AI ready ## Fontsource plugin ## Grouped selectors ## At (@) prop and breakpoints ## Design tokens ## Powerful TypeScript types ## Passing styles using spread ## Target children ## Server components ready ## Style boundaries ## React Native ## Use it as a companion to Tailwind ## Variants and class composition ## Gotchas ## ESLint plugin ## Closing notes ## Why "CSS-in-JS" is in quotes ## Generated files ## What's next? Before I get into the details there are a few things I want to clarify. I'm not a content creator or writer, and I don't want to be. For this reason, this will be one single, detailed, long ass post. I'll try to explain and justify the choices I made inspired by my past experiences. It'll also serve as some sort of initial documentation. In case you want to read about the library itself and skip its history, jump here: Boss CSS I'm coding mostly for web for 22 years now, and for 17 professionally. I've used several different ways to do CSS, using all kinds of frameworks, methodologies, different styling solutions, compilers and architectures. We always change for the better, trying to overcome the problems our previous solution suffered from. But this doesn't mean the new solution performs better in all areas, always leaving a gap behind. My first stop was using raw CSS. To solve organization issues, I started to split files into multiple chunks. To simplify selector usage, I've started to use LESS and SASS with support for nesting. To solve issues with naming and avoid selector collision, I was using methodologies like Atomic CSS and BEM. To simplify usage in the codebase and enable tree-shaking, I started to use CSS Modules. To improve DX, I started to use CSS-in-JS based solutions. To solve runtime performance issues, I started to use build-time static extraction. I started to use Tailwind, because it's lightweight and framework agnostic. All the solutions are coming with their own strengths and flaws, which would deserve their own articles. Around 8 years ago, I chose Grommet as the UI layer for a project. I immediately fell in love with their Box component, but I still ended up writing custom style objects for specific needs. A few years later, on another project, I ended up creating my own Box component. At the end it got quite complex and still, it didn't give me full CSS support, which again required me to write custom style objects and custom class names in CSS files. This was the time when CCSS and YouEye were born. It fundamentally changed how I wrote and used CSS. I'm still using them in production today, but (as it should) they started to reveal their own weaknesses over time. The last couple of years it became unavoidable to work with Tailwind on a project. I'm using it both in personal and professional projects. It's a classic love-hate relationship. I always loved the idea of utility classes and Atomic CSS. In fact, I've created my first utility class based CSS framework on top of SASS 11 years ago. It was generating utility classes based on configuration, then it was purging the final CSS based on usage. The final results were actually pretty close to Tailwind's AOT compiler. However, I have some problems using Tailwind: Please note that at the time of writing this, we only had Tailwind v2 available. It came a long way since then, solving many problems, especially around custom CSS. I understand those who are in favor of Tailwind over native CSS. It actually solves a lot of quirks and issues coming with native CSS. I believe it's a much better choice for those who started web development in the last couple of years or have a more backend-heavy background and feel uncomfortable writing CSS directly. However, I spent a lot of years learning, understanding and overcoming these problems. In most cases, I simply want to write CSS, and Tailwind just doesn't give me that. I actually never intended to write another CSS-in-JS library. But over the years I had so many thoughts about what I'd do differently, how I'd solve certain problems. Sometimes I had sleepless nights thinking about styling in different ways. Over time, these thoughts piled up and I've started to connect the dots in my mind. Last year, during such a night, I've decided to get up and test a few things in an online playground. It was the moment when I decided to start this new project, because I felt like I could offer something new. The biggest question for me: which solution made me the happiest, the most productive, and had the best possible balance in terms of both DX and UX? For me it was prop-based CSS-in-JS with static and dynamic extraction. Since working remotely I've joined several short-term projects either as a developer or consultant. I've seen dozens of cases where projects had their own Box component, each of them suffering from different flaws. This was also a fueling factor, because I know it could be better, I did use better in the past. When I first started to work on this new library, my goal was to create a solution that's tooling independent. YouEye and many existing tools are mostly relying on custom Babel plugins by parsing and modifying AST at build time. I moved away from Babel years ago due to performance reasons, first to ESBuild then to SWC. I wanted a way that works regardless of the stack a project is using. Tailwind introduced such a way: parse on your own. Initially, I simply wanted to have prop-based CSS-in-JS that's extracted as Atomic CSS, while having a lightweight runtime that doesn't emit or manipulate stylesheets. I also wanted to make sure that it's fairly easy to extend its functionality, which led me to an event-based solution for its overall architecture. Soon I realized that this deep control enables me to add support for different syntaxes and extraction strategies, so users can decide which combination suits their project best. This is the reason for the name Boss, it lets you be in control. I spent a lot of my free time working on the library. Unfortunately, I don't really have much time next to my family and work, which led to very slow progress. At the beginning of 2024 I also had some personal issues, which forced me to pause every personal project. This slow progress definitely caused some fragmentation in my code. However, I spent so much time working on this and I truly believe it offers something new, I simply don't want it to go to waste. For the above reasons I decided to bring the project into shape for an early Alpha release. I did, it was 90% ready. However after 3 months of sleepless nights and grinding next to work and the fam, I hit a rough burnout phase. Only some minor bugfixes, documentation, website, playground and such were left. I spent so much time away from the project that I ended giving it up. Last year I slowly moved over to vibe-coding. Today, I mostly just review and instruct the agent's work. I decided to "revive" the project in the middle of boredom. This time with AI only, taking care of all the missing parts. Well, from this point I quickly got into the rabbit hole, asking the AI to add features I previously planned to implement in a future version, features I didn't even want to implement. It only took ~4 weeks of some free time to finish all this. Not the best quality of results, but it works enough. My hope is that it'll gain some traction in the community, which would force me to find a way to work on it more seriously. I hope to get some help to shape its rough edges, and help to build reliable documentation. In case those things don't happen, I still wanted to put it out there and hopefully inspire fellow developers with some ideas my solution brings to the table. Honestly, I'm not even sure if the lib has relevance nowadays in this AI era. When building Boss, I tried to bring the best parts of different styling solutions I used over the years. While that is subjective, I believe I achieved that for the most part. I often see libraries and frameworks coming with custom props, custom namings for some cases, like the p and m prop only for margin and padding, but nothing else, or consolidating font-* and text-* properties under a single prefix. These add extra learning curves, and can disrupt the flow of those coming with a heavy native CSS background. Parity with CSS naming and syntax was one of the most important goals for me. I wanted to be able to write CSS as it is as much as possible, without having to translate it in my head to some custom syntax. Class name based styling is basically almost inline styles by look. If you know CSS, you know 98% of Boss. I'm going to showcase all the different syntaxes supported out of the box. Why support multiple syntax? Because it lets you mix-n-match according to your own preferences, and your own specific needs/use cases. Prop-based styling is the default for me for a long time now. I simply love it more than anything else. It comes with great flexibility, handles dynamic cases very well, is highly customizable for different design system needs, and can be perfectly typed. Read more in the Docs: JSX usage. Using class names is really convenient, but when it comes to dynamic cases, this is where it can get messy. In Boss, using class names really just looks like using inline styles. It has almost identical syntax, with the additional benefit of targeting states, pseudo elements, media queries, keyframes, tokens, and more. Read more in the Docs: Classname usage. It's basically prop-based styling with a different syntax, but if you prefer objects instead of props, no problem. (I know in this example it doesn't look any different from an ordinary style object, and that's a good thing.) A concept Styled Components popularized in the first place, and it's really handy to create reusable elements. Read more in the Docs: Prepared components. If needed, you can still append raw CSS blocks with $$.css template string/object forms. It remains useful for custom selectors and one-off rules. Because sometimes we still need it. Because sometimes we need it. An optional plugin that provides Tailwind-like shorthands and tokens out-of-the-box. In this example I used class names for static styles, and props for dynamic cases, as well as the hover prop instead of multiple hover:* classes. Read more in the Docs: Bosswind. As you might have seen in the previous examples, prop-based styling is done through a custom component, which might make you think runtime is required. And you're not wrong. However, you have the option to compile away all the components to native elements in a bundler-agnostic way, or just use class names, which doesn't need runtime. Why I call Boss a polymorphic CSS-in-JS library is because Boss includes runtime based on your usage. In case you're only using class names with classname-only, runtime files won't be generated at all. Plugins can determine when and what code to include based on how you're using styles. This makes it possible to use Boss class names in basically any stack/environment, regardless of framework or programming language. Having a lightweight runtime can be just as good as not having any, but the most important part is that it can give superpowers. There are many never-seen features in my head utilizing runtime, and I'm eager to share them over time. One I can share is the experimental devtool: when you select a DOM element on the page, you can adjust its styling or source code right in the browser, hit save, and it writes the changes back to the source file, without leaving the browser. This polymorphism also applies to TypeScript types and AI files. Boss generates TS types, AI docs, and AI skills based on your configuration, updating them based on your usage. It supports types for custom properties, prepared components and design tokens as well. Boss runtime also works differently compared to classic CSS-in-JS solutions. In inline-first and classname-first it does not generate full stylesheets on every render. In runtime-only mode it can inject only the needed rules on the client. You can also go hybrid, and have both pre-generated CSS at build time and runtime support for highly dynamic cases, for example when users modify styles or certain rules come from a 3rd-party source. This is one of the biggest ideas behind the architecture. Read more in the Docs: Runtime strategy. Boss supports different extraction strategies. Again, this is to facilitate different needs. This is the default strategy. Boss prioritizes inline styles, putting everything possible inline, saving a large chunk of external, initial and unused CSS. Performance is arguable. You can find studies saying inline styles are faster and just as many saying it's slower. In my opinion it's circumstantial. But even if it tends to be slower in some cases, you save time on loading external stylesheets, which are normally blocking requests delaying FCP. In the above case we only have external CSS for the hover state. This is the opposite of inline first. It uses class names wherever possible and keeps inline only where unavoidable (for example user-flagged dynamic cases using CSS variables). This approach is close to Tailwind-like output. There are projects which need full runtime support and need to generate styles on the fly. Projects with complex WYSIWYG editors or page styles coming from separate databases. Full runtime support is for these cases. Boss supports this with the runtime strategy (runtime.only: true) and also supports hybrid mode (runtime.only: false) when you want server CSS output plus runtime dynamics. It is possible to transform source to native HTML elements, classes and style objects at build time, leaving runtime out completely. Today this can be achieved through: Simple compile example: Read more in the Docs: Compile, Classname-only strategy. What I dislike about many extraction tools is that they are mostly tied to a custom compiler integration (Babel plugin, framework plugin, bundler lock-in). Boss is intentionally different here. Boss is built to run through PostCSS, CLI build/watch, or compile mode, without requiring Babel/Webpack/Vite-specific plugins. That makes it easier to carry the same styling API across React, React Native, Next, Preact, Solid, Qwik, Stencil, and non-JSX/non-JS setups using static class names. Read more in the Docs: Tooling agnostic. It's time to write about other random features and goodies Boss supports. By default, you can access Boss components and utilities using the $$ global variable. Whoever is old enough to have worked with jQuery can't argue that accessing $ everywhere was pure simplicity, and with inline styles the feeling is no different. Besides, you don't want to import Boss in every single file where you write markup, just as much as you would not want to do import { div, a, span, section } from 'react'. It's so powerful that basically every feature of Boss is just a plugin. The core is mainly the event system. Plugins are split into server/browser code: server controls compile-time tasks, browser code ends up in your production bundle when needed. Example for a simple custom prop plugin: Numeric values use Boss's built-in unit conversion (api.unit), so there is no need for manual ${v}px. Read more in the Docs: Plugin hooks. Boss also ships CLI tools for the full workflow: So whether you're on PostCSS or a custom/non-PostCSS setup, you still have a clear path to bootstrap, build, watch, and optimize. Read more in the Docs: CLI. Boss has built-in AI readiness through the AI plugin. It can generate LLMS.md plus an AI skills bundle from your live configuration and usage metadata (tokens, breakpoints, prepared components, strategy context, and more). This means agents can work with project-specific styling context, not just generic guesses. Read more in the Docs: AI plugin. Boss can load fonts from the Fontsource catalog through the fontsource plugin, and injects the needed CSS when fonts is configured. Read more in the Docs: Fonts and Fontsource. You can use multiple styles inside one state/pseudo while using class names. I have to admit that generated selectors for these are not always pretty. But it works, it's there, and it's nice to have. Besides, if you use compiler, that will split up such selectors for you. You can write responsive styles with at and with shorthand breakpoints. ClassName equivalent: Built-in defaults include micro, mobile, tablet, small, medium, large, and device, with name, name+, and name- forms. It also supports arbitrary values and ranges, such as mobile-800. Boss also supports container queries through container, containerType, containerName, and container_* shorthands. ClassName equivalent: Read more in the Docs: Pseudo and @ / responsive contexts. You can access tokens in different ways: TypeScript hints include available token values for each property. Boss also supports DTCG/Style Dictionary token JSON and resolves references/inheritance, which makes existing design token pipelines easier to plug in. On top of this, Boss supports local token theming with the tokens prop, so you can scope theme overrides to a subtree. This is also best shown as a parent override + child inheritance case: Token strings also support alpha suffixes, for example: And for DTCG users, composite token types like border, shadow, transition, gradient, and typography are normalized into CSS-ready values. Read more in the Docs: Tokens. Boss generates type-safe CSS props from real CSS definitions, token-aware props, and prepared component types into .bo$$/index.d.ts. Boss supports marker/helper APIs for spread-heavy patterns: For plain elements, use $$.style(...): Read more in the Docs: Spreads and markers. Boss supports arbitrary nested selectors both in JSX (child) and class names ([ ... ] syntax). Read more in the Docs: Classname usage. Boss works with modern server-first frameworks (including Next.js patterns). For Next.js you wire runtime with instrumentation hooks and import CSS manually when css.autoLoad is disabled (which init does by default for Next). Read more in the Docs: Next.js integration. Boss can split generated CSS by directory using *.boss.css boundaries. This lets you load only what you need while shared rules can hoist to common ancestors or global styles. Boundary files stay empty in source and are overwritten by Boss on build/watch/postcss runs. Read more in the Docs: CSS boundaries. I've used YouEye in Expo projects, creating cross-device components and I loved it. You can achieve the same with Boss as well. Boss can generate native runtime output (.bo$$/native.js, .bo$$/native.d.ts) using the same $$ API while mapping props to React Native styles/components. Read more in the Docs: React Native usage. Boss class names do not collide with Tailwind's by default, which means you can use them together. You can use Boss for CSS cases Tailwind doesn't support, or to handle dynamic cases more nicely. If you want a more Tailwind-like flavor inside Boss itself, there is Bosswind for aliases/booleans on top of the same pipeline. Boss includes $$.cx, $$.cv, $$.scv, $$.sv (and direct imports) for class/style composition patterns. This makes conditional/variant flows cleaner than hand-rolled class merging. The $$ component's className also has built-in support for cx. Read more in the Docs: Class composition and variants. Boss has its own gotchas as well. A few important ones: This one already exists now, and I consider it essential. Boss can be used in many different ways, thus it can be abused just as much. Linting gives control to your projects to keep everything in line. Read more in the Docs: ESLint plugin. Boss sits in an in-between space. Depending on strategy, it can look like classic CSS-in-JS, static extraction, utility-class generation, or runtime-only behavior. That's why I keep putting it in quotes. Generated files can look messy. Necessary? In my opinion, yes (kinda). They are the practical output of the polymorphic approach, and they keep source authoring clean while letting the pipeline adapt to usage. Nothing. I'm not intending to work on this project for now. I just wanted to put it out there, and hopefully inspire some people with the ideas behind it. If it gains traction, maybe I'll find a way to work on it more seriously, but for now, it's done. I'm using it myself in a project now, it helps reveal some rough edges and bugs which I might or might not fix. The playground is WebContainer-powered and runs a full Vite + React project in the browser, with editor, terminal, and preview. It also has ready starter templates and shareable URL state, so you can deep-link a template (https://bosscss.com/playground#template=boss-bosswind) or share your exact workspace setup. If you're curious, this is the fastest place to try ideas, push edge cases, and see how Boss behaves before touching your local setup. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse COMMAND_BLOCK:
<$$ color="red"> Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
<$$ color="red"> COMMAND_BLOCK:
<$$ color="red"> CODE_BLOCK:
<div className="color:red"> Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
<div className="color:red"> CODE_BLOCK:
<div className="color:red"> CODE_BLOCK:
<span {...$$.style({ color: 'red' })}> Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
<span {...$$.style({ color: 'red' })}> CODE_BLOCK:
<span {...$$.style({ color: 'red' })}> COMMAND_BLOCK:
$$.MyStyledContainer = $$.$({ width: 1200,
}) const Component = () => <$$.MyStyledContainer>...</$$.MyStyledContainer> Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
$$.MyStyledContainer = $$.$({ width: 1200,
}) const Component = () => <$$.MyStyledContainer>...</$$.MyStyledContainer> COMMAND_BLOCK:
$$.MyStyledContainer = $$.$({ width: 1200,
}) const Component = () => <$$.MyStyledContainer>...</$$.MyStyledContainer> CODE_BLOCK:
$$.css(` #element .selector ul li { /* my custom css */ }
`) Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
$$.css(` #element .selector ul li { /* my custom css */ }
`) CODE_BLOCK:
$$.css(` #element .selector ul li { /* my custom css */ }
`) CODE_BLOCK:
<$$.a className="display:flex place-content:center" color={linkColor} hover={{ background: 'red', borderBottom: '1px solid #000' }}
> Click me!
</$$.a> Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
<$$.a className="display:flex place-content:center" color={linkColor} hover={{ background: 'red', borderBottom: '1px solid #000' }}
> Click me!
</$$.a> CODE_BLOCK:
<$$.a className="display:flex place-content:center" color={linkColor} hover={{ background: 'red', borderBottom: '1px solid #000' }}
> Click me!
</$$.a> COMMAND_BLOCK:
// As classNames
<$$ className="flex px:1 text:xl" />
// As props
<$$ flex px={1} text="xl" /> Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
// As classNames
<$$ className="flex px:1 text:xl" />
// As props
<$$ flex px={1} text="xl" /> COMMAND_BLOCK:
// As classNames
<$$ className="flex px:1 text:xl" />
// As props
<$$ flex px={1} text="xl" /> COMMAND_BLOCK:
<$$ color="red" hover={{ color: 'yellow' }} /> Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
<$$ color="red" hover={{ color: 'yellow' }} /> COMMAND_BLOCK:
<$$ color="red" hover={{ color: 'yellow' }} /> CODE_BLOCK:
<div class="hover:color" style="color: red; --hover-color: yellow" /> Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
<div class="hover:color" style="color: red; --hover-color: yellow" /> CODE_BLOCK:
<div class="hover:color" style="color: red; --hover-color: yellow" /> COMMAND_BLOCK:
<$$ color="red" hover={{ color: 'yellow' }} /> Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
<$$ color="red" hover={{ color: 'yellow' }} /> COMMAND_BLOCK:
<$$ color="red" hover={{ color: 'yellow' }} /> CODE_BLOCK:
<div class="color:red hover:color:yellow" /> Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
<div class="color:red hover:color:yellow" /> CODE_BLOCK:
<div class="color:red hover:color:yellow" /> CODE_BLOCK:
npx boss-css compile Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
npx boss-css compile CODE_BLOCK:
npx boss-css compile COMMAND_BLOCK:
// input
const Example = () => <$$ color="red" padding={8} /> // output
const Example = () => <div style={{ color: 'red', padding: '8px' }} /> Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
// input
const Example = () => <$$ color="red" padding={8} /> // output
const Example = () => <div style={{ color: 'red', padding: '8px' }} /> COMMAND_BLOCK:
// input
const Example = () => <$$ color="red" padding={8} /> // output
const Example = () => <div style={{ color: 'red', padding: '8px' }} /> COMMAND_BLOCK:
// .bo$$/plugins/bleed/server.js
export const name = 'bleed-prop' export const onBoot = api => { api.dictionary.set('bleed', { property: 'margin', aliases: ['bleed'], description: 'Custom bleed prop', isCSSProp: true, })
} export const onProp = async (api, { name, prop, contexts }) => { if (name !== 'bleed') return api.css.selector({ className: api.contextToClassName(name, prop.value, contexts), }) api.css.rule('margin', prop.value) api.css.write()
} Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
// .bo$$/plugins/bleed/server.js
export const name = 'bleed-prop' export const onBoot = api => { api.dictionary.set('bleed', { property: 'margin', aliases: ['bleed'], description: 'Custom bleed prop', isCSSProp: true, })
} export const onProp = async (api, { name, prop, contexts }) => { if (name !== 'bleed') return api.css.selector({ className: api.contextToClassName(name, prop.value, contexts), }) api.css.rule('margin', prop.value) api.css.write()
} COMMAND_BLOCK:
// .bo$$/plugins/bleed/server.js
export const name = 'bleed-prop' export const onBoot = api => { api.dictionary.set('bleed', { property: 'margin', aliases: ['bleed'], description: 'Custom bleed prop', isCSSProp: true, })
} export const onProp = async (api, { name, prop, contexts }) => { if (name !== 'bleed') return api.css.selector({ className: api.contextToClassName(name, prop.value, contexts), }) api.css.rule('margin', prop.value) api.css.write()
} CODE_BLOCK:
// .bo$$/config.js
import * as bleedProp from './plugins/bleed/server' export default { plugins: [bleedProp /* ... */],
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// .bo$$/config.js
import * as bleedProp from './plugins/bleed/server' export default { plugins: [bleedProp /* ... */],
} CODE_BLOCK:
// .bo$$/config.js
import * as bleedProp from './plugins/bleed/server' export default { plugins: [bleedProp /* ... */],
} COMMAND_BLOCK:
<$$ bleed={-14} /> Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
<$$ bleed={-14} /> COMMAND_BLOCK:
<$$ bleed={-14} /> CODE_BLOCK:
npx boss-css init
npx boss-css build
npx boss-css watch
npx boss-css compile
npx boss-css dev Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
npx boss-css init
npx boss-css build
npx boss-css watch
npx boss-css compile
npx boss-css dev CODE_BLOCK:
npx boss-css init
npx boss-css build
npx boss-css watch
npx boss-css compile
npx boss-css dev COMMAND_BLOCK:
import * as fontsource from 'boss-css/fontsource/server' export default { plugins: [fontsource, /* ... */], fonts: [{ name: 'Inter', token: "body" }],
} <$$ fontFamily="body" /> Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
import * as fontsource from 'boss-css/fontsource/server' export default { plugins: [fontsource, /* ... */], fonts: [{ name: 'Inter', token: "body" }],
} <$$ fontFamily="body" /> COMMAND_BLOCK:
import * as fontsource from 'boss-css/fontsource/server' export default { plugins: [fontsource, /* ... */], fonts: [{ name: 'Inter', token: "body" }],
} <$$ fontFamily="body" /> CODE_BLOCK:
<div class="hover:{color:red;text-decoration:underline} mobile:{width:100vh;background:blue}"></div> Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
<div class="hover:{color:red;text-decoration:underline} mobile:{width:100vh;background:blue}"></div> CODE_BLOCK:
<div class="hover:{color:red;text-decoration:underline} mobile:{width:100vh;background:blue}"></div> COMMAND_BLOCK:
<$$ at={{ 'mobile+': { fontSize: 18 } }} />
<$$ tablet={{ fontSize: 18 }} /> Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
<$$ at={{ 'mobile+': { fontSize: 18 } }} />
<$$ tablet={{ fontSize: 18 }} /> COMMAND_BLOCK:
<$$ at={{ 'mobile+': { fontSize: 18 } }} />
<$$ tablet={{ fontSize: 18 }} /> CODE_BLOCK:
<div class="at:mobile+:display:block" />
<div class="mobile:hover:display:block" /> Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
<div class="at:mobile+:display:block" />
<div class="mobile:hover:display:block" /> CODE_BLOCK:
<div class="at:mobile+:display:block" />
<div class="mobile:hover:display:block" /> COMMAND_BLOCK:
<$$ containerType="inline-size" containerName="card"> <$$.div container_card={{ mobile: { fontSize: 18 } }}>Child reacts to the parent container</$$.div>
</$$> Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
<$$ containerType="inline-size" containerName="card"> <$$.div container_card={{ mobile: { fontSize: 18 } }}>Child reacts to the parent container</$$.div>
</$$> COMMAND_BLOCK:
<$$ containerType="inline-size" containerName="card"> <$$.div container_card={{ mobile: { fontSize: 18 } }}>Child reacts to the parent container</$$.div>
</$$> CODE_BLOCK:
<div class="container-type:inline-size container-name:card"> <div class="container_card:mobile:font-size:18">Child reacts to the parent container</div>
</div> Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
<div class="container-type:inline-size container-name:card"> <div class="container_card:mobile:font-size:18">Child reacts to the parent container</div>
</div> CODE_BLOCK:
<div class="container-type:inline-size container-name:card"> <div class="container_card:mobile:font-size:18">Child reacts to the parent container</div>
</div> COMMAND_BLOCK:
<$$ tokens={{ color: { brand: '#ea580c' }, spacing: { md: 20 } }}> <$$ color="brand" padding="md"> Parent with local token override </$$> <$$.span color="brand">Child inherits the same scoped token override</$$.span>
</$$> Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
<$$ tokens={{ color: { brand: '#ea580c' }, spacing: { md: 20 } }}> <$$ color="brand" padding="md"> Parent with local token override </$$> <$$.span color="brand">Child inherits the same scoped token override</$$.span>
</$$> COMMAND_BLOCK:
<$$ tokens={{ color: { brand: '#ea580c' }, spacing: { md: 20 } }}> <$$ color="brand" padding="md"> Parent with local token override </$$> <$$.span color="brand">Child inherits the same scoped token override</$$.span>
</$$> COMMAND_BLOCK:
<$$ color="gray.600/60" /> Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
<$$ color="gray.600/60" /> COMMAND_BLOCK:
<$$ color="gray.600/60" /> COMMAND_BLOCK:
const props = $$.$({ color: 'red', hover: { color: 'purple' } }) <$$ {...props} /> Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
const props = $$.$({ color: 'red', hover: { color: 'purple' } }) <$$ {...props} /> COMMAND_BLOCK:
const props = $$.$({ color: 'red', hover: { color: 'purple' } }) <$$ {...props} /> CODE_BLOCK:
<div {...$$.style({ padding: 12, hover: { color: 'purple' } })} /> Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
<div {...$$.style({ padding: 12, hover: { color: 'purple' } })} /> CODE_BLOCK:
<div {...$$.style({ padding: 12, hover: { color: 'purple' } })} /> COMMAND_BLOCK:
<$$ child={{ '.title': { color: 'blue' }, '&>div': { color: 'red' } }} /> Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
<$$ child={{ '.title': { color: 'blue' }, '&>div': { color: 'red' } }} /> COMMAND_BLOCK:
<$$ child={{ '.title': { color: 'blue' }, '&>div': { color: 'red' } }} /> CODE_BLOCK:
<div class="[&_.title]:font-weight:700" /> Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
<div class="[&_.title]:font-weight:700" /> CODE_BLOCK:
<div class="[&_.title]:font-weight:700" /> CODE_BLOCK:
src/ app/ app.boss.css page.tsx admin/ admin.boss.css page.tsx
.bo$$/styles.css Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
src/ app/ app.boss.css page.tsx admin/ admin.boss.css page.tsx
.bo$$/styles.css CODE_BLOCK:
src/ app/ app.boss.css page.tsx admin/ admin.boss.css page.tsx
.bo$$/styles.css CODE_BLOCK:
// src/app/layout.tsx
import './app.boss.css' Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// src/app/layout.tsx
import './app.boss.css' CODE_BLOCK:
// src/app/layout.tsx
import './app.boss.css' CODE_BLOCK:
// .bo$$/config.js
import * as native from 'boss-css/native/server' export default { plugins: [native /* ... */],
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// .bo$$/config.js
import * as native from 'boss-css/native/server' export default { plugins: [native /* ... */],
} CODE_BLOCK:
// .bo$$/config.js
import * as native from 'boss-css/native/server' export default { plugins: [native /* ... */],
} COMMAND_BLOCK:
export default function App() { return ( <$$ padding={12}> <$$.Text>Native UI</$$.Text> </$$> )
} Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
export default function App() { return ( <$$ padding={12}> <$$.Text>Native UI</$$.Text> </$$> )
} COMMAND_BLOCK:
export default function App() { return ( <$$ padding={12}> <$$.Text>Native UI</$$.Text> </$$> )
} COMMAND_BLOCK:
<$$ className={{ 'display:none': isHidden }} /> Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
<$$ className={{ 'display:none': isHidden }} /> COMMAND_BLOCK:
<$$ className={{ 'display:none': isHidden }} /> - I always end up in situations where I have to keep maintaining a separate styling solution for custom needs. Tailwind is only a subset of CSS and it won't cover every area.
- The naming of selectors: I wouldn't be able to count on my 2 hands how many times I've Googled the term tailwind line-height, because of course, it's leading and I keep forgetting that. What's font-size in CSS, it's text-[size] in Tailwind. These minor differences are driving me crazy, and in some cases it's seriously interrupting my flow.
- Dynamic cases: whether Tailwind or CSS Modules, I always disliked merging class names using 3rd-party utilities, and by hand using conditions.
- States and pseudo elements: I hate using hover 5 times just to style my hover state.
- Breakpoints: I always hated mobile-first approaches, especially nowadays when it doesn't really make sense anymore. - classname-only strategy for static class usage
- npx boss-css compile for source transformation and runtime pruning in supported cases - <$$ color="primary">
- <$$ color={$$.token.color.primary}>
- <div className="color:primary">
- <div className="color:$$.token.color.primary"> - Token autocompletion and token value hints
- Prepared component typing/JSDoc metadata
- Native runtime typings (native.d.ts) when React Native runtime is enabled - ClassName parsing supports static strings only. Dynamic template interpolation is intentionally skipped.
- In runtime.only, className parsing is disabled (runtime only handles props and nested contexts).
- classname-only has zero runtime, so no dynamic function values.
- Compile mode currently focuses on JSX and the main extraction strategies.
- ClassName autocomplete in TS is naturally limited because strings are strings. ESLint helps here. - Website: https://bosscss.com
- Repository: https://github.com/wintercounter/boss
- Playground: https://bosscss.com/playground
how-totutorialguidedev.toaimlllmserverdatabasegitgithub