<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Anton Evzhakov</title>
    <description>The latest articles on DEV Community by Anton Evzhakov (@anber).</description>
    <link>https://dev.to/anber</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4024519%2F91d3f9e5-0a4b-4303-a2d3-c451108b94ea.jpg</url>
      <title>DEV Community: Anton Evzhakov</title>
      <link>https://dev.to/anber</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anber"/>
    <language>en</language>
    <item>
      <title>The state of zero-runtime CSS-in-JS, mid-2026</title>
      <dc:creator>Anton Evzhakov</dc:creator>
      <pubDate>Mon, 27 Jul 2026 05:57:41 +0000</pubDate>
      <link>https://dev.to/anber/the-state-of-zero-runtime-css-in-js-mid-2026-5ci6</link>
      <guid>https://dev.to/anber/the-state-of-zero-runtime-css-in-js-mid-2026-5ci6</guid>
      <description>&lt;p&gt;Two disclosures before the map. I maintain Linaria, and I built dx-styles, one of the libraries below. You are reading a biased cartographer. The bias is labeled, the facts are linked, and corrections are welcome: file an issue and I will fix the map loudly.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we got here
&lt;/h2&gt;

&lt;p&gt;For most of a decade, CSS-in-JS meant a runtime: styled-components and Emotion computed styles during render and injected them into the document. It was a great authoring model, and it worked because React rendered synchronously on the client and nowhere else.&lt;/p&gt;

&lt;p&gt;Then React changed shape underneath it. Concurrent rendering made render-time style injection a performance liability. Server Components made client-side style runtimes structurally awkward: there is no good place to inject styles from a component that never ships to the browser. The ecosystem read the signals. styled-components went into &lt;a href="https://styled-components.com/blog/celebrating-a-decade-of-styled-components" rel="noopener noreferrer"&gt;maintenance mode in March 2025&lt;/a&gt;. MUI started Pigment CSS as a compile-time successor for its own needs, then &lt;a href="https://github.com/mui/pigment-css" rel="noopener noreferrer"&gt;put it on hold in alpha&lt;/a&gt;. The default advice became "just use Tailwind," which is fine advice for many teams, though the surveys describe a complicated relationship: &lt;a href="https://2025.stateofreact.com/en-US/libraries/component-libraries/" rel="noopener noreferrer"&gt;State of React 2025&lt;/a&gt; calls it love/hate, and "excessive Tailwind usage" is the only framework entry in &lt;a href="https://2025.stateofcss.com/en-US/usage/#css_general_pain_points" rel="noopener noreferrer"&gt;State of CSS 2025's general pain points&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What survived on the CSS-in-JS side is the branch that never needed a runtime in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why compile-time is the branch that lived
&lt;/h2&gt;

&lt;p&gt;The idea is old and simple: styles written in JS or TS are data, and data can be evaluated at build time. The compiler runs your style declarations during the build, writes real .css files, and leaves plain class-name strings in your JavaScript. Nothing injects anything at runtime, there is no provider, and nothing needs to cross the Server Component boundary, because by the time React runs, styling is just strings.&lt;/p&gt;

&lt;p&gt;You keep the parts people actually liked about CSS-in-JS: styles colocated with components, typed values, tokens as code. You pay for it with a build step and with discipline about what can be statically evaluated. That trade is the whole category.&lt;/p&gt;

&lt;h2&gt;
  
  
  The map
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;vanilla-extract&lt;/strong&gt; is the TypeScript answer to CSS Modules. Styles live in separate &lt;code&gt;.css.ts&lt;/code&gt; files, themes are typed contracts, and the recipes package covers variant-driven components. It is mature, stable, and predictable. The main friction is the file split: styles do not live in the component file, and some teams never stop missing that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Panda CSS&lt;/strong&gt; is config-first and atomic: you describe tokens, recipes, and patterns in a config, a codegen step produces a styled-system folder, and output CSS is deduplicated utility classes. It has the richest ecosystem in the category and reads familiar to people coming from Chakra. The costs are the codegen artifact in your repo and the atomic model itself, which is a real trade-off rather than a free win: great dedup at app scale, opaque class soup in DevTools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;StyleX&lt;/strong&gt; is Meta's production system: atomic output, strict constraints, deterministic merging, designed for codebases with thousands of contributors. The constraints are the feature. If your problem is "hundreds of teams keep overriding each other's styles," StyleX solves something almost nothing else solves. If your problem is smaller than that, the constraints mostly show up as friction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;next-yak&lt;/strong&gt; takes the opposite entrance: keep the styled-components authoring model, compile it away. A Rust compiler turns styled syntax into static CSS, dynamic props become CSS custom properties, and the result is RSC-compatible with production numbers to back it at &lt;a href="https://yak.js.org/" rel="noopener noreferrer"&gt;Digitec Galaxus scale&lt;/a&gt;. If you have a large styled-components codebase and want off the runtime without a rewrite, this is the newest of the two direct paths, and the fastest-building one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linaria&lt;/strong&gt; is the original zero-runtime library and the reason half this category exists. It was built as a drop-in replacement for styled-components, and it still is one: the same styled syntax, no runtime. It is maintained and stable; new engine work happens in &lt;a href="https://github.com/Anber/wyw-in-js" rel="noopener noreferrer"&gt;wyw-in-js&lt;/a&gt;, the compiler underneath it. That shared engine has a practical consequence: Linaria code and dx-styles code extract in one build, so the two can coexist and migrate file by file. For brand-new design-system work I would point you at the newer generation, and I say that as Linaria's maintainer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;dx-styles&lt;/strong&gt; is my entry, so read this paragraph with the disclosure in mind. It is built on the same wyw-in-js engine as Linaria, but API-first for design systems: semantic deterministic class names, typed recipes and slot recipes, token contracts instead of theme conventions, opt-in compile-time RTL. It also answers the question every compiled pipeline eventually gets asked: the explain tooling traces any class in the emitted CSS back to the exact source declaration that produced it. If you are building a component library rather than an app, that is the niche it was made for. The launch post explains &lt;a href="https://dx-styles.dev/blog/why-dx-styles/" rel="noopener noreferrer"&gt;why it exists&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Honorable mention: &lt;strong&gt;Griffel&lt;/strong&gt;, Microsoft's atomic engine under Fluent UI. It descends from an early Linaria fork and serves Fluent well, but it is its own ecosystem with little interop outside it.&lt;/p&gt;

&lt;p&gt;And the honest exits: &lt;strong&gt;Tailwind&lt;/strong&gt; and &lt;strong&gt;CSS Modules&lt;/strong&gt; are not CSS-in-JS, and for plenty of teams they are the right answer. Leaving the category entirely is a legitimate migration target, not a failure state.&lt;/p&gt;

&lt;h2&gt;
  
  
  The same map as a table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;dx-styles&lt;/th&gt;
&lt;th&gt;Linaria&lt;/th&gt;
&lt;th&gt;next-yak&lt;/th&gt;
&lt;th&gt;vanilla-extract&lt;/th&gt;
&lt;th&gt;Panda CSS&lt;/th&gt;
&lt;th&gt;StyleX&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Zero runtime&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes ¹&lt;/td&gt;
&lt;td&gt;yes ¹&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;mostly ²&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Styles colocated in components&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;no (&lt;code&gt;.css.ts&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recipes / slot recipes&lt;/td&gt;
&lt;td&gt;yes / yes&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;no (styled API)&lt;/td&gt;
&lt;td&gt;yes ³ / no&lt;/td&gt;
&lt;td&gt;yes / yes&lt;/td&gt;
&lt;td&gt;pattern, not API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Token contracts + themes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;manual CSS vars&lt;/td&gt;
&lt;td&gt;manual CSS vars ⁴&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compile-time RTL&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;not documented&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;logical properties&lt;/td&gt;
&lt;td&gt;logical properties&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Status&lt;/td&gt;
&lt;td&gt;active&lt;/td&gt;
&lt;td&gt;maintained, stable&lt;/td&gt;
&lt;td&gt;active&lt;/td&gt;
&lt;td&gt;active&lt;/td&gt;
&lt;td&gt;active&lt;/td&gt;
&lt;td&gt;active&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;¹ Dynamic interpolations in the styled API compile to CSS custom properties.&lt;br&gt;
² Ships a small runtime for style merging.&lt;br&gt;
³ Via &lt;code&gt;@vanilla-extract/recipes&lt;/code&gt;.&lt;br&gt;
⁴ next-yak cells reflect its public docs as of 9.7; corrections welcome.&lt;/p&gt;

&lt;p&gt;Pigment CSS is missing from the table on purpose: it remains in alpha and on hold, and recommending it today would not be a kindness. There are &lt;a href="https://github.com/dx-styles/dx-styles/tree/main/docs/migration" rel="noopener noreferrer"&gt;migration guides&lt;/a&gt; off it, mine included.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to choose
&lt;/h2&gt;

&lt;p&gt;Skip the feature grids and start from your situation.&lt;/p&gt;

&lt;p&gt;You have a big styled-components codebase and the runtime hurts: two direct paths keep your syntax. next-yak compiles it away with a Rust toolchain and, credit where due, builds faster. Linaria is the veteran drop-in, and its shared engine with dx-styles makes it double as an on-ramp: land on Linaria first, then drift toward recipes and token contracts file by file in the same build, with no second migration event.&lt;/p&gt;

&lt;p&gt;You are building an app and want typed styles with minimal ceremony: vanilla-extract if you accept the file split, Panda if you want atomic output and a batteries-included config.&lt;/p&gt;

&lt;p&gt;You are building a component library or a design system: you want semantic stable class names, typed variants, and token contracts that survive being consumed by other people's builds. That is dx-styles' niche, and vanilla-extract is the other serious candidate.&lt;/p&gt;

&lt;p&gt;You operate at hundreds-of-teams scale and your enemy is style collisions: StyleX, and take the constraints as the point.&lt;/p&gt;

&lt;p&gt;You mostly want to stop thinking about this: Tailwind or CSS Modules, honestly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the category is heading
&lt;/h2&gt;

&lt;p&gt;Convergence, from every direction at once. Every surviving library compiles to some flavor of "plain element with class names." Even the styled authoring model now folds away at build time rather than executing at runtime. The differences that remain are real but narrower: atomic versus semantic output, config-first versus code-first authoring, and how much of the design-system layer (tokens, variants, slots) is first-class API versus your own convention.&lt;/p&gt;

&lt;p&gt;Build cost is becoming the next battleground now that runtime cost is largely solved, and it is converging too. Independent numbers exist for part of the field: &lt;a href="https://jantimon.github.io/css-in-js-bench/" rel="noopener noreferrer"&gt;css-in-js-bench&lt;/a&gt; measures both runtime behavior and build overhead across seventeen techniques, though the wyw-in-js family is not in it yet. I am publishing a reproducible build-time harness covering that side as a follow-up post, with numbers you can rerun rather than take on faith.&lt;/p&gt;

&lt;p&gt;The map will be wrong in six months, which is the healthiest thing I can say about this category. File corrections, I will keep it honest.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Anton Evzhakov maintains Linaria and is the author of wyw-in-js, the zero-runtime engine behind Linaria and MUI's Pigment CSS. He builds dx-styles.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>css</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>I've maintained Linaria for six years. Here's why I built something new</title>
      <dc:creator>Anton Evzhakov</dc:creator>
      <pubDate>Fri, 10 Jul 2026 21:16:16 +0000</pubDate>
      <link>https://dev.to/anber/ive-maintained-linaria-for-six-years-heres-why-i-built-something-new-5eae</link>
      <guid>https://dev.to/anber/ive-maintained-linaria-for-six-years-heres-why-i-built-something-new-5eae</guid>
      <description>&lt;p&gt;Runtime CSS-in-JS is winding down. styled-components has been in maintenance mode since early 2025, Server Components made the runtime model a structural dead end, and the default advice is "just use Tailwind." That advice is fine — for many teams it's correct, though the surveys read like a complicated romance: &lt;a href="https://2025.stateofreact.com/en-US/libraries/component-libraries/" rel="noopener noreferrer"&gt;State of React 2025&lt;/a&gt; calls it a love/hate relationship, and "excessive Tailwind usage" is the only framework entry in &lt;a href="https://2025.stateofcss.com/en-US/usage/#css_general_pain_points" rel="noopener noreferrer"&gt;State of CSS 2025's general pain points&lt;/a&gt;. But if what you actually want is typed styles, tokens, and variants living next to your components, the zero-runtime branch of CSS-in-JS is where that lives, and I've spent the last six years in it: I maintain Linaria, and I'm the author of &lt;a href="https://github.com/Anber/wyw-in-js" rel="noopener noreferrer"&gt;wyw-in-js&lt;/a&gt; — the compile-time engine that powers Linaria and MUI's Pigment CSS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/dx-styles/dx-styles" rel="noopener noreferrer"&gt;dx-styles&lt;/a&gt; is what I built after all of that. This post is about why it exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  What six years of zero-runtime CSS-in-JS taught me
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Two problems I couldn't fix in Linaria
&lt;/h3&gt;

&lt;p&gt;They came back over and over in the issue tracker, and neither is fixable without breaking what Linaria is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First: &lt;code&gt;styled(Component)&lt;/code&gt; is priced wrong.&lt;/strong&gt; Wrapping a custom component looks like free composition — &lt;code&gt;styled(ButtonWithIcons)&lt;/code&gt; and you're done. In practice the wrapped component drags its entire dependency graph — icons, hooks, half of your utils — into build-time evaluation. That's the single most common way extra code leaks into eval, and the most common reason static evaluation gives up and falls back to actually running your module. Every mitigation we shipped over the years — explicit HOC hints in plugin options, dedicated heuristics for shaking wrapped components — is a patch on a pattern the API itself encourages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second: composition.&lt;/strong&gt; Linaria hands you &lt;code&gt;css&lt;/code&gt; and &lt;code&gt;cx&lt;/code&gt; and wishes you luck. People have asked for style fragments for years, and I've pushed back every time: fragments would add chaos and complexity without addressing the actual need. In a real design system, variants, slots, and themes aren't advanced tricks — they're the ground floor. They belong in the styling library as first-class citizens, not as conventions every team reinvents on top of it.&lt;/p&gt;

&lt;p&gt;Both fixes move the center of gravity of the API. Remove &lt;code&gt;styled&lt;/code&gt; — or even demote it — and you've broken most of what's built on Linaria. So Linaria stays what it is, and stays maintained. The next thing had to be a new thing.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Pigment CSS taught me
&lt;/h3&gt;

&lt;p&gt;MUI built Pigment CSS on wyw-in-js, then put it on hold. My takeaway wasn't about MUI — it was about &lt;strong&gt;speed&lt;/strong&gt;. On a greenfield project, build time is a habit you form early. But when you &lt;em&gt;migrate&lt;/em&gt; an existing codebase and the styling step suddenly costs 10× the rest of the build, that's a dealbreaker — I watched it happen. And 10× isn't the ceiling: I've seen style builds take tens of minutes and tens of gigabytes of RAM.&lt;/p&gt;

&lt;p&gt;That experience pushed wyw-in-js toward static evaluation: prove what can be proven at build time, skip the evaluation sandbox entirely. The results so far are honestly mixed — but codebases that evaluate fully statically build several times faster. And the pattern that most reliably ruins static evaluation is the one from problem #1: &lt;code&gt;styled(Component)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;dx-styles isn't perfect here either. A few of its processors still hit the JS fallback — creating a token contract does, in some shapes. That's a known, solvable problem, and the fix lands with wyw-in-js@3 and dx-styles@2.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update (July 24): this shipped earlier than promised. The static-evaluation work landed in wyw-in-js 2.2 and 2.3, and as of dx-styles 1.3.0 the token-contract fallback is gone.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The trigger
&lt;/h2&gt;

&lt;p&gt;My team started a component library from scratch, and Linaria turned out to be awkward in exactly the places a design system lives: tokens, variants, multipart components. We tried Griffel — itself a Linaria descendant, but through a fork that diverged around Linaria 3 and grew into a separate engine with no cross-compatibility with the wyw ecosystem: atomic classes didn't fit what we were building, and our custom processors would have meant maintaining two extraction pipelines side by side. At some point the conclusion was hard to avoid: we had more accumulated mileage with zero-runtime CSS-in-JS than anyone else, and we were spending it on working around our own tooling.&lt;/p&gt;

&lt;h2&gt;
  
  
  What dx-styles is
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createTheme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createTokenContract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;recipe&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dx-styles&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createTokenContract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;accent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;accentFg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dark&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;accent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#7c8cff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;accentFg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#080a12&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;recipe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inline-flex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;999px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;variants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;appearance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accentFg&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;ghost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;transparent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accent&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;defaultVariants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;appearance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// &amp;lt;button className={button({ appearance: "ghost" })} /&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At build time this becomes a static CSS file and plain class-name strings. Deterministic semantic classes you can snapshot and cache on. Recipes and slot recipes with typed variants. Token contracts instead of theme conventions. Opt-in compile-time RTL. No style runtime, no providers — and the same components work unchanged in React Server Components.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I didn't expect to be the best part
&lt;/h2&gt;

&lt;p&gt;dx-styles is implemented as a set of wyw-in-js processors — and processors aren't limited to styles. In a commercial product I work on, the same build step that extracts CSS also statically executes parts of application logic and inlines the results, dropping dead weight from the bundle at compile time. It's a macro mechanism you get for free with your styling pipeline. Writing your own processor next to dx-styles is a supported extension point, not a hack — and every wyw-based library interoperates in the same build.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm promising — and what I'm not
&lt;/h2&gt;

&lt;p&gt;dx-styles is MIT and stays MIT. The issue tracker runs at zero open issues — and I owe you honesty about how. If you've followed Linaria closely, you may have noticed maintenance slowing down through 2024–2025: boring triage was quietly eating the entire energy budget. Since last October, agents have taken over that layer — turning reports into reproductions, bisecting regressions — and maintainer time goes into the actual engineering; the fixes I still mostly write by hand. That's the economics that makes zero-open-issues sustainable, and dx-styles gets it from day one.&lt;/p&gt;

&lt;p&gt;wyw-in-js@3 has a written plan — the high-level roadmap is public (&lt;a href="https://wyw-in-js.dev/stability#roadmap-high-level" rel="noopener noreferrer"&gt;stability page&lt;/a&gt;, &lt;a href="https://github.com/Anber/wyw-in-js/issues/114" rel="noopener noreferrer"&gt;tracking issue&lt;/a&gt;) and the detailed plan goes further. The honest constraint is volume: it's a lot of work, and its pace will scale with how much the community cares about this direction. No dates.&lt;/p&gt;

&lt;p&gt;Try it without installing anything: the &lt;a href="https://stackblitz.com/github/dx-styles/dx-styles/tree/main/examples/vite" rel="noopener noreferrer"&gt;Vite starter on StackBlitz&lt;/a&gt; is a ready-made sandbox — a themed button demo you can poke, edit, and watch the extracted CSS change; the &lt;a href="https://stackblitz.com/github/dx-styles/dx-styles/tree/main/examples/next" rel="noopener noreferrer"&gt;Next.js one&lt;/a&gt; runs the same components inside React Server Components. Prefer starting from scratch? &lt;code&gt;npm install dx-styles&lt;/code&gt; and the &lt;a href="https://github.com/dx-styles/dx-styles/blob/main/docs/getting-started.md" rel="noopener noreferrer"&gt;getting started guide&lt;/a&gt;. Migrating? There are dedicated guides for &lt;a href="https://github.com/dx-styles/dx-styles/blob/main/docs/migration/from-styled-components.md" rel="noopener noreferrer"&gt;styled-components&lt;/a&gt;, &lt;a href="https://github.com/dx-styles/dx-styles/blob/main/docs/migration/from-linaria.md" rel="noopener noreferrer"&gt;Linaria&lt;/a&gt;, and &lt;a href="https://github.com/dx-styles/dx-styles/blob/main/docs/migration/from-pigment-css.md" rel="noopener noreferrer"&gt;Pigment CSS&lt;/a&gt;. Issues — including hostile questions — welcome: &lt;a href="https://github.com/dx-styles/dx-styles" rel="noopener noreferrer"&gt;github.com/dx-styles/dx-styles&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Anton Evzhakov — maintainer of Linaria; author of wyw-in-js, the zero-runtime engine behind Linaria and MUI's Pigment CSS.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>css</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
