# Salty CSS > Build-time CSS-in-TS for React, Next.js and Astro. Compiles `styled(...)` calls > in `*.css.ts` files to plain CSS at build time — zero runtime cost, with full > TypeScript autocomplete on design tokens, themes, variants and media queries. > Works with React Server Components. Salty CSS is a TypeScript-first CSS-in-TS library with its own build-time compiler — not a fork of vanilla-extract, Stitches or Linaria. The docs below are mirrored across React, Next.js and Astro; each is the same content with framework-specific install steps and code snippets — pick the one that matches your stack. Full documentation: https://new-website.salty-css.dev/llms-full.txt (all frameworks) Per-framework: https://new-website.salty-css.dev/llms-full-react.txt | https://new-website.salty-css.dev/llms-full-next.txt | https://new-website.salty-css.dev/llms-full-astro.txt ## Overview - [Salty CSS](https://new-website.salty-css.dev/): Build-time CSS-in-TS library for React, Next.js, Astro and React Server Components, built with TypeScript. - [Salty CSS for React](https://new-website.salty-css.dev/react/): Sprinkle Salty CSS on your React app — build-time CSS-in-TS that ships zero runtime. - [Salty CSS for Next.js](https://new-website.salty-css.dev/next/): Salty CSS in the App Router — zero-runtime styles that work with React Server Components. - [Salty CSS for Astro](https://new-website.salty-css.dev/astro/): The same styled API in .astro files and React islands, extracted to plain CSS at build time. ## Documentation (React) - [Styled Components](https://new-website.salty-css.dev/docs/react/index): A walkthrough of the styled() API in Salty CSS: the four ideas it is shaped around (build-time execution, components over class names, variants as layers, primitives over UI kits), deconstructing the options object (base, variants, defaultVariants, element), when to reach for className() instead, composing independent atoms into a card, and extending an existing component into a new cascade layer. - [Styling Basics](https://new-website.salty-css.dev/docs/react/basics): Styling Basics ## Documentation (Next.js) - [Styled Components](https://new-website.salty-css.dev/docs/next/index): A walkthrough of the styled() API in Salty CSS: the four ideas it is shaped around (build-time execution, components over class names, variants as layers, primitives over UI kits), deconstructing the options object (base, variants, defaultVariants, element), when to reach for className() instead, composing independent atoms into a card, and extending an existing component into a new cascade layer. - [Styling Basics](https://new-website.salty-css.dev/docs/next/basics): Styling Basics ## Documentation (Astro) - [Styled Components](https://new-website.salty-css.dev/docs/astro/index): A walkthrough of the styled() API in Salty CSS: the four ideas it is shaped around (build-time execution, components over class names, variants as layers, primitives over UI kits), deconstructing the options object (base, variants, defaultVariants, element), when to reach for className() instead, composing independent atoms into a card, and extending an existing component into a new cascade layer. - [Styling Basics](https://new-website.salty-css.dev/docs/astro/basics): Styling Basics ## Concepts - [Why Salty CSS Exists](https://new-website.salty-css.dev/concepts/why-salty-css-exists): The story behind Salty CSS — what shaped it, where it came from, who it's for, and an honest accounting of where things stand now. ## Optional - [Styled Components](https://new-website.salty-css.dev/docs/react/basics/styled-components): A walkthrough of the styled API in Salty CSS: the four ideas it is shaped around (build-time execution, components over class names, variants as layers, primitives over UI kits), deconstructing the options object (base, variants, defaultVariants, element), when to use className instead, composing independent atoms into a card, and extending an existing component into a new cascade layer. - [Breakpoints & responsive layouts](https://new-website.salty-css.dev/docs/react/basics/breakpoints): A walkthrough of responsive conditions in Salty CSS, built on one idea: you name a condition once and reference it by @name inside any style object, the same way you reference a token by path. Covers the three tools — inline raw at-rules for one-offs, named queries via defineMediaQuery for everything else, and responsive tokens or viewport clamp when a single value changes rather than a block of styles. Warns that a definition file must reach the build once or the @name silently emits an at-rule that never matches. Four examples: naming a breakpoint set centrally and the min-width versus max-width direction choice, going past width to dark mode, print, reduced motion and orientation with the and/or combining builder, container queries that let a component respond to its container rather than the viewport including container query units, and the cases where a breakpoint is the wrong tool because the change is really one value moving smoothly. - [Animations](https://new-website.salty-css.dev/docs/react/basics/animations): A walkthrough of motion in Salty CSS, framed as three tools with a lightest-first instinct: transitions where the browser tweens between two states it already tracks, keyframes() for genuinely multi-step or self-running motion, and state-driven motion where an attribute flip plus a transition replaces both a keyframe and React state. Covers transitions as plain CSS needing no special API; keyframes() with from/to, percentage-string and numeric keys, the hard rule that every call must be a top-level export of a .css.ts file, the callable return value that lets one definition be reused at different timings, the full timing-params table with defaults, and appendInitialStyles which inlines the starting frame so a delayed animation does not flash. Covers keyframes as variants, staggering a list of any length with a {props.index} prop token rather than a per-index variant, and pausing declaratively with the animationPlayState longhand. Example 4 builds an on-scroll entrance from an attribute, a global style using a :not() selector, and an IntersectionObserver — no keyframe, no state, no dependency — including the honest catch that content hidden by default stays invisible if the script never runs. Closes with the private-helper pattern for stamping out a family of related keyframes. - [Modifiers](https://new-website.salty-css.dev/docs/react/basics/modifiers): A walkthrough of modifiers in Salty CSS: a value shape you invent plus a rule for what Salty rewrites it into, registered as a regex pattern and a transform function in salty.config.ts. Places modifiers between templates (which give you a new key) and dynamic values (which give you a new expression): a modifier keeps the property you were always going to write and teaches its value a shape Salty recognises. Documents the three facts that decide whether a pattern fires — the pattern is tested against the finished declaration including property name and semicolon rather than the bare value, tokens are already resolved to var() references before modifiers run, and transform receives the whole matched string rather than capture groups — plus the fact that modifiers run in declaration order, each seeing the previous one output. Four worked examples: a spacing scale that does arithmetic and throws on off-scale values, flex-center returning extra declarations via the css key, a color opacity suffix built on color-mix() including a progressive-enhancement fallback, and a line-clamp modifier that hides a vendor-prefixed compat workaround. Closes with a four-way comparison against tokens, templates and helpers, and the gotchas including that every modifier is a word with no autocomplete and no typo checking. - [Viewport Clamp](https://new-website.salty-css.dev/docs/react/basics/helpers/viewport-clamp): A walkthrough of defineViewportClamp in Salty CSS: a helper that builds a native CSS clamp() from a reference screen size, so a value scales continuously between a floor and a ceiling instead of stair-stepping at breakpoints. Covers what it replaces and why a size that stays proportioned to the layout it was designed in means fewer breakpoints and fewer awkward in-between states. Documents defining one clamp per device target with screenSize, minMultiplier, maxMultiplier and axis; calling it with the value the property should have at the reference size, on any size property rather than font-size alone; the three parts of the generated clamp and how screenSize anchors the fluid middle; per-call min and max overrides; and a worked resolution table across common viewport widths. The main pattern is building responsive design tokens by calling the clamp inside defineVariables so the whole spacing and type system scales together and components read plain token paths. Includes a full options reference and the edge cases: inverted min and max, a reference size larger than any real viewport, negative multipliers, and axis selection. - [Color Function](https://new-website.salty-css.dev/docs/react/basics/color-function): A walkthrough of the color() helper in Salty CSS: a chainable function for lightening, darkening, adjusting alpha, mixing and rotating hue, all resolved at build time so the transformed value lands in the generated CSS as a plain static string. Leads with the boundary that matters most — color() can only transform values it can see at build time, meaning raw colors and static token references, while responsive or conditional tokens and {props.X} values pass through unchanged, so shades are derived from static atoms rather than themed molecules. Covers basic chaining, the palette-derivation pattern where one source color generates a family of tokens, and keeping interactive states in tune with a base color. Full reference of accepted color sources, the transparency, lightness, saturation, hue and blend methods, the output format methods, the sRGB parsing and HSL-internal transform model, the lack of wide-gamut support, and the build-time throw behaviour on unparseable input. - [Helpers](https://new-website.salty-css.dev/docs/react/basics/helpers): A walkthrough of helpers in Salty CSS: a helper is a plain function you import and call to produce a style value, called once while styles compile with the result baked into the static stylesheet. There is no registration step and no compiler hook. Shows how to write your own with a pixel-to-rem example, and the habit of keeping pure value-returning helpers in plain .ts modules so style files stay light. Tours the two built-ins — defineViewportClamp for fluid clamp() sizing tuned to a reference screen, replacing a stack of media queries, and color() for chainable build-time color manipulation whose most common use is deriving a family of shades from one brand color. Includes a decision table separating helpers from tokens, templates and modifiers: a token is for a fixed named value, a template for a bundle of properties, a modifier for a new value syntax, and a helper for logic that computes a value from arguments. Notes that helpers compose, can be async, and should keep heavy dependencies out of .css.ts files. - [Scoping and composition](https://new-website.salty-css.dev/docs/react/basics/scoping-and-composition): A walkthrough of scoping and composition in Salty CSS. Scoping has two jobs that pull in opposite directions: isolation, which Salty handles by giving every styled component and className a hashed class, and deliberate overriding, which is most of this page. Covers nesting with & and how every nested selector compiles anchored to the component hash so it physically cannot leak; targeting another Salty component by identity by interpolating its hash into a selector rather than relying on a tag; adding a shared opt-in class for a whole family of components with the className option, and the boundary that styling that class from a scoped parent is fine while reaching for it from an unscoped global stylesheet is not; a three-rung override ladder of variant, then style prop, then a CSS custom property with a fallback; composition by wrapping a styled component, which inherits variants and auto-bumps into the next cascade layer, with passProps for variant names that collide with real HTML attributes; and the precedence model itself, including the fixed layer order and the counterintuitive rule that !important inverts layer precedence so the earlier layer wins. - [Runtime styles](https://new-website.salty-css.dev/docs/react/basics/runtime-styles): A walkthrough of defineRuntime in Salty CSS: a request-time helper that takes a style object and returns a className and css pair, for input that does not exist when the project compiles. Explains that this is not a way to move style generation off the build, and gives a four-rung ladder — build-time styled or className, prop tokens when only one value is unknown, runtime styles when the style object itself arrives with the request, and a plain style prop for per-frame changes. Covers why an inline style is not a substitute (no states, no breakpoints, no child selectors), the setup loop in a plain .ts file rather than a .css.ts one, why passing config connects incoming token and breakpoint names to the same values components use, the deterministic hash that enables deduplication, and the resolve, css and className members. Two worked cases: profile customization where you build the style object field by field from validated data, and one-off CMS block overrides. Documents the feature support table, the fact that runtime CSS is emitted without a cascade layer and therefore outranks every layered rule by construction, and the security posture — Salty deliberately does not sanitize runtime style input. - [Accessibility](https://new-website.salty-css.dev/docs/react/basics/accessibility): A guide to what Salty CSS can and cannot do for accessibility. It cannot solve the hard problems — a combobox, a modal, drag-and-drop reorder — but it removes a set of small excuses that produce most real component-tree bugs. Nine define-then-use patterns: rendering the element the job calls for by keeping tag and looks as separate knobs with as and element, and the link-versus-button distinction; semantic wrappers that cost nothing in layout via display: contents, with its three sharp edges including the Safari list-semantics bug that role=list fixes; binding attributes to the component with defaultProps so nobody has to remember them; styling off the ARIA attribute so visual and announced state cannot drift, plus the counterweight that no ARIA beats bad ARIA; hover and focus in one rule using :focus-within and a forgiving :where() group, and why opacity rather than display is what makes it work; turning motion off with a named reduced-motion query and a global backstop that deliberately uses !important because layer inversion is the mechanism; nudging a colour until it is legible while being clear that color() does not compute contrast ratios; the two different things high contrast means, prefers-contrast versus forced-colors; and zoom, including the non-obvious fact that vw units do not respond to page zoom, which makes a clamp's minMultiplier the thing standing between a fluid type scale and an unzoomable one. - [Tooling](https://new-website.salty-css.dev/docs/react/basics/tooling): A tour of the tooling around Salty CSS: TypeScript, one CLI, one ESLint plugin, with no language server or editor extension. Explains that most of the type layer is generated by your own definitions — add a token and it autocompletes, name a media query and it becomes a valid object key, define a text style and its paths appear — because the compiler writes a declaration file into saltygen on every build. Documents the two practical consequences (types follow the build, and the editor can hold a stale copy) and the honest half: style values are permissive strings by design, so a typo'd token path is caught by strict at build time rather than by the editor, and a wrong filename type-checks perfectly while producing no CSS. Covers the four CLI commands with what init touches in full, the .saltyrc.json that shortens every other command, and the two ESLint rules — must-be-exported and no-variants-in-base — with why each failure is invisible to TypeScript and what the autofix does. Closes with the data-component-name attribute for reading output in DevTools. - [Testing](https://new-website.salty-css.dev/docs/react/basics/testing): A guide to testing in a Salty CSS project, split by the three different questions people mean by "testing": does this component still behave, does it look right, and did the compiler emit what I wrote. Establishes the public surface — the element, its attributes, the variant props, and any class you named yourself — against the internal one, being the generated hashes and the saltygen folder, which are safe to read but never to assert on. Explains what a test runner can actually see and why cascade layers in DOM emulators mean unit tests are for behaviour and structure while browsers are for appearance. Documents why the content-addressed hash breaks three different kinds of test, and the two stable hooks that replace it: the className option and defaultProps binding real roles and ARIA attributes. Covers getting .css.ts files through a runner and the CSS-stub pattern that silently swallows them, end-to-end selectors and the data-component-name attribute that only exists in development, and visual regression where themes are one attribute and fonts are the thing that will actually bite. Then reading output in the browser — component names in the tree, two classes rather than forty, which layer won, live custom properties, and forcing states DevTools can emulate — and finally checking the build without running the app. - [Security](https://new-website.salty-css.dev/docs/react/basics/security): A security guide for Salty CSS. Establishes the baseline: .css.ts files are evaluated in Node during the build, the result is one static stylesheet, and there is no style injection during render — the only styling code in the client bundle is a mapper picking pre-compiled class names from variant props. Four things sit outside that guarantee: styles arriving as data at request time, values a user hands to a prop token, stylesheets from someone else's server, and the build itself. Calibrates what a style object can actually do — the old url(javascript:) and expression() tricks are dead, but CSS still makes network requests, owns the interface, and can stop being CSS if a payload escapes its style element. Documents that defineRuntime deliberately does not sanitize and why, with a worked validation pattern that builds the style object from validated fields, plus four edge details: the scope argument is a selector, raw-HTML sinks like Astro's set:html, capping payload size, and knowing which threat model applies. Covers the narrower but not closed prop-token rung, remote CSS and the lack of Subresource Integrity for @import, the build as code with everything it emits being public, and a Content Security Policy section covering style-src-attr for prop tokens and nonces for runtime style elements. - [Class Names](https://new-website.salty-css.dev/docs/react/basics/class-names): A walkthrough of the className() API in Salty CSS: the same options object styled() takes, returning a class string rather than a component. Covers the options object (className, base, variants), the .variant() chain and the fact that it returns a new String object rather than a primitive, defaultVariants being accepted but not applied automatically and the wrapper-function pattern that fixes it, handing classes to markup you do not own via a react-select multi-slot example, applying classes to plain DOM from a script including the classList.add split and the bundler-reachability requirement, using className as the authoring API on frameworks with no styled, and the four component ergonomics className deliberately does not have (extending, element/as/passProps/defaultProps, automatic defaultVariants, css-* prop tokens). - [Dynamic Values](https://new-website.salty-css.dev/docs/react/basics/dynamic-values): A walkthrough of the ways a Salty CSS style value can be decided by code rather than typed as a literal, and where each one resolves. The governing rule is that almost everything resolves at build time: a variable, an import, a function or a promise is run once while compiling and the result is baked into the static stylesheet. Five examples: a value held in a local const, which vanishes into the output; a value authored as a real CSS custom property with a fallback so a parent can turn the knob later; a computed value including an async function whose fetch runs once at build and is then frozen for every visitor; sharing values across files, with the warning that whatever a .css.ts file imports is imported into the build and the proportion note that plain data modules are free; and typed {props.X} prop tokens exposed as css-* JSX props, which is the one mechanism on the page that stays live in the browser because the value is genuinely the consumer to pick. - [Interactive State](https://new-website.salty-css.dev/docs/react/basics/interactive-state): A walkthrough of styling interactive state in Salty CSS as a four-rung ladder you climb only as far as the state forces you to. Rung 1 is state the browser already tracks — hover, active, disabled, plus the commonly forgotten :focus-within, :user-invalid, :user-valid and :placeholder-shown, the native open attribute on details, ARIA and data attributes as free styling hooks, and both directions of relational styling with :has() and nested descendant selectors, all anchored to the component hash so nothing leaks. Rung 2 is app state the browser cannot see, modelled as a closed variant axis driven by React state, with the attribute alternative for external state machines and the reason variants remain the default (a data attribute is unscoped and can match across nesting levels). Documents the disabled trap in full: a disabled variant styles a button that stays clickable because variant props do not reach the DOM, the two fixes (leave it native, or add it to passProps), and the genuine exception for non-form elements which need aria-disabled instead. Rung 3 is open-ended values via {props.X} prop tokens, which ride a real CSS variable to the browser. Rung 4 is a conditional theming group pointed at a state axis so a whole region repaints from one attribute. - [Variants](https://new-website.salty-css.dev/docs/react/basics/variants): A walkthrough of variants in Salty CSS: a named branch of a style picked at the call site and compiled to CSS before the app runs. Covers why a variant beats a second component, a render-time style object or a loose class name, and the cost that every declared value is compiled whether used or not. Documents the five shared keys (variants, defaultVariants, compoundVariants, anyOfVariants, and the boolean true/false form) and the three activation routes: props on styled with defaults applied, .variant() chaining on className with defaults not applied, and name@variant strings inside defineTemplates. Covers compoundVariants as AND, anyOfVariants as OR emitted inside :where() with zero specificity, and the four limits — closed sets only, not lifting state the browser already tracks, axis multiplication, and defineFont variants being an unrelated use of the same word. - [Variables & Tokens](https://new-website.salty-css.dev/docs/react/basics/variables): A walkthrough of design tokens in Salty CSS: defining values with defineVariables and referencing them as {path.to.token} with build-time path validation. Explains why Salty says "variables" rather than "tokens" or "theme", and that everything resolves at build time into plain custom properties on :root with no runtime token system. Covers the three scopes — static tokens on :root, the responsive scope that swaps a value per media query while the name stays put, and the conditional scope that swaps a value when an ancestor selector matches, which is the mechanism theming is built on. Also covers the dashed naming of compiled properties, naming tokens by role rather than raw value, mixing all three scopes in one call, the gotcha that a standalone defineVariables file must reach the build graph to take effect, and sharing tokens across a monorepo. - [Theming](https://new-website.salty-css.dev/docs/react/basics/theming): A walkthrough of theming in Salty CSS: variables are the raw values, theming is the switchable layer on top, and flipping one attribute on an ancestor repaints everything beneath it through the native variable cascade with no re-render. Establishes the atoms-and-molecules split — fixed palette entries are atoms used to define themes, role-named contextual values are molecules that components are built against — and the two scopes: conditional flips on an ancestor selector for user- or markup-driven switches, responsive flips on a media query for environment-driven ones. Notes the build-time boundary where the color() helper can transform atoms but not molecules. Four worked examples: light and dark shown first as compiled CSS then as authoring, extended with extra schemes and theme-aware interactive states; many molecules per theme for named profile looks; nested themes and independent conditional groups that avoid writing out N times M combinations; and automatic light and dark keyed to prefers-color-scheme via the responsive scope, where the consumption side is identical and only the definition moves. - [Templates](https://new-website.salty-css.dev/docs/react/basics/templates): A walkthrough of templates in Salty CSS: bundling several property-value pairs under one name with defineTemplates and applying them as a key inside a component base. Explains the CSS shorthand mental model, that templates are not for whole components (a styled component already is your card), and that templates resolve in their own templates cascade layer below component styles so anything set directly on the component still wins. Covers five worked cases: text styles with a shared base and per-size leaves plus opt-in variants and no defaultVariants, base-only interaction-state templates applied with true, a border-like preset template and why it must not be named after a real CSS shorthand, theming templates that reference themed molecule tokens rather than raw brand colors, and function templates that take a call-site argument — a single value or a typed options object — and run as plain TypeScript at build time. Also notes leaf inheritance of base and variants, responsive tokens flowing through text styles with no media query, and {props.X} injection as the one template feature with a runtime cost. - [Global Styles](https://new-website.salty-css.dev/docs/react/basics/global-styles): A walkthrough of global styles in Salty CSS: the deliberate exception to default scoping, for rules that belong to the whole document rather than one component. Covers the two places to declare them — defineGlobalStyles in a .css.ts file, or defineConfig({ global }) — and the gotcha that a stranded file that never reaches the build graph silently does nothing. Explains where they land in the cascade: the global layer sits above reset so your globals beat the reset without !important, and below l0 so component styles always beat a global selector no matter how specific it looks. Includes a worked document base with tokens and nested selectors, a note on pragmatic document-wide utility classes and where that stops being appropriate, an explicit good-fits and not-this list, the four dedicated factories that own global CSS instead of defineGlobalStyles (defineVariables, defineFont, defineTemplates, defineImport), and the built-in reset with its configuration options. - [Fonts & Imports](https://new-website.salty-css.dev/docs/react/basics/fonts): A walkthrough of defineFont and defineImport in Salty CSS, two factories for getting CSS that isn't a styled component into the build. States up front that defineFont writes correct @font-face CSS and nothing more — no subsetting, no automatic preloading, unlike next/font — so loading-performance practices stay the author's to own. Covers defining a local font as a variants array with one entry per @font-face rule, the src, fallback and display inputs, and the four members the returned object exposes (fontFamily which it stringifies to, variable, className and style). Covers hosted fonts via the mutually exclusive import option, and the modular pattern of pairing defineFont with defineVariables so components reference a role token like fontFamily.body rather than a typeface. Includes the @font-face practices that matter: serving WOFF2, one face per weight and style with real descriptors so the browser does not synthesize, choosing font-display deliberately, preloading critical fonts by hand, cutting layout shift with the metric override fields, subsetting with unicodeRange, and CORS on font origins. Documents defineImport for plain stylesheets, one call per named export, the warning about stacking a third-party reset on top of Salty's own, conditional imports via media and supports, and the fact that everything from defineImport lands in the earliest cascade layer and therefore always loses to your own component styles. - [Basic setup](https://new-website.salty-css.dev/docs/react/getting-started/basic-setup): A getting-started guide for adding Salty CSS to a project. npx salty-css init reads package.json, picks the framework, installs the right packages, drops salty.config.ts next to the bundler config, wires the plugin and creates saltygen/. Notes that the real compatibility question is not which framework you use but whether your dev server runs on Vite or Webpack. Documents the manual install as five steps plus a per-stack table of plugin packages and wiring, with worked setups for Next.js (one withSaltyCss wrapper covering both Webpack and Turbopack, and importing the stylesheet for you), React with Vite, React with Webpack where saltyPlugin mutates the config in place, and Astro which has its own docs. Covers the empty-but-working config file, then a first component with the two rules that quietly do the work — the filename suffix and the export — and how the component is used with nothing to wrap, register or provide. - [API overview](https://new-website.salty-css.dev/docs/react/getting-started/api-overview): A map of the whole Salty CSS public surface, organised by job rather than by module. Opens with the two steps everything follows — define something in a file the compiler reads, then reference it by name — and the five reference syntaxes: {token} for a variable, {theme.x} for a themed one, {props.x} for a consumer-supplied value, @name for a media query used as a key, and a template name used as a key. Then five lookup tables: getting styles onto something (styled, className, defineGlobalStyles, defineRuntime, and plain nesting), reusing a decision (variables, theming, templates, modifiers, helpers), making styles react to something (media and container queries, nesting for browser-tracked state, variants for closed app state, prop tokens for open-ended values), bringing other things in (fonts, imports, keyframes, color), and the project itself (config, CLI, ESLint). Documents where every symbol is imported from and that the react paths are straight re-exports of core. Closes with four tie-breakers for the pairs that come up most, and an explicit list of what Salty deliberately does not include — no layout primitives, no component kit, no sanitization in defineRuntime, and no editor extension. - [Configuration](https://new-website.salty-css.dev/docs/react/getting-started/configuration): A walkthrough of configuring a Salty CSS project. Establishes two framings: Salty leans toward more files rather than fewer, and the names you choose here ship as CSS variable names, HTML attributes and autocompleted strings. Documents salty.config.ts, which must sit next to the bundler config because that is where the plugin looks, and defineConfig whose entire job is TypeScript. Separates the five compiler-behaviour options that only live in the config (strict, defaultUnit, importStrategy, externalModules, reset) from the four that are design-system content and can move into their own files (variables, global, templates, and the config-only exception modifiers). Tours every define* factory with a minimal example and its import path: defineVariables, defineGlobalStyles, defineTemplates, defineMediaQuery, defineFont, defineImport, keyframes and defineViewportClamp, plus the note that defineRuntime is not one of them. Explains that nothing is imported at the call site because tokens, query names and template keys are strings the compiler resolves, and the two rules that make that work — a recognized filename suffix and a top-level export — both of which fail quietly. Covers where each kind of name lands, and .saltyrc.json which tells the CLI where projects are rather than how to build CSS. - [Editor setup](https://new-website.salty-css.dev/docs/react/getting-started/editor-setup): A once-per-project setup guide for the editor side of Salty CSS. There is no extension and no language server: the compiler lives inside the bundler and everything the editor knows arrives through a declaration file the build writes into saltygen/, which any TypeScript-aware editor reads like any other .d.ts. Covers what that buys you — token paths autocompleting inside style objects, wrong paths greyed out, variants becoming typed union props — and three settings worth checking: pointing the editor at the project's TypeScript 5.x rather than a bundled older copy, the fact that types follow the build so a fresh clone has nothing to suggest, and that the TS server can hold a stale copy after adding a token. Explains what TypeScript will not catch, since style values are permissive strings by design, and that strict in the config is what catches an unresolvable token path instead. Documents the ESLint plugin and the two mistakes invisible to TypeScript that it exists for — an unexported definition and variants nested inside base — plus fix-on-save. Closes with the prepare script that regenerates saltygen after a fresh clone, and the two places that still catch people out: installs with --ignore-scripts, and mixed package versions. - [File structure](https://new-website.salty-css.dev/docs/react/getting-started/file-structure): A guide to the two sets of files in a Salty CSS project: the ones you write, where the only thing the compiler cares about is the filename, and the ones Salty writes, which you never edit but can read like any other text file. Covers the five compiling suffixes and the export half of the contract, that file placement is entirely free because the compiler walks by suffix, how include/exclude scope that walk, and why a file containing any defineX( call compiles twice. Documents the two config files and what each one tells Salty, and the single root import. Then maps saltygen/ in full: index.css as a table of contents whose banner gives the writing version, whose @layer line is the whole override story, and whose absent imports signal a discovery problem rather than a write failure; the css/ prefix namespaces (_, cl_, a_, l_, f_); the six fixed globals and what an empty one means; the cl_ naming where the filename carries the export name and the class inside is the bare hash derived from the style object only, with deduplication as a consequence; the layer bundles and their fence markers; the generated token declaration file and the empty-union signal; and the js/ and cache/ working folders. Closes with a backwards-debugging workflow, the three different hash lengths, and the difference between what a full build and an incremental save actually write. - [Advanced setup](https://new-website.salty-css.dev/docs/react/getting-started/advanced-setup): The layer after Basic setup: the small set of shared files that turn one component into part of a system. None of it is required to ship and none of it changes runtime behaviour, because it all compiles into the same static stylesheet. Opens with where the files live — a shared /styles folder split by what each file defines — and the rule that the compiler finds files by suffix rather than by import, so the only two requirements are the filename and a top-level export, both of which fail quietly. Notes that salty.config.ts takes the same objects directly and that strict: true is how you make the quiet failures loud. Then a glimpse of each shared piece with a define half and a use half: variables and the name-by-role habit, theming and the one layer of indirection that makes it work, breakpoints named once and referenced by @name, fonts and the honest boundary that defineFont writes correct @font-face and nothing more, templates as a shorthand for properties that travel together, and global styles as the deliberate exception to scoping. Closes with what the shared layer unlocks back in the component — variants, interactive state and scoping, animations, helpers — and three things deliberately one step further on. - [Troubleshooting](https://new-website.salty-css.dev/docs/react/getting-started/troubleshooting): A debugging guide for Salty CSS, ordered by how often each cause is the actual cause. Opens with a two-minute DevTools triage that splits the problem three ways: no hashed class means the file never reached the compiler, a hashed class with no matching rule means the CSS never reached the page, and a struck-through or literal value means something else is winning or a value never resolved. First-time setup covers the file that type-checks perfectly and emits nothing (the filename suffix), the definition nothing exports, salty.config.ts not being where the plugin looks, the plugin never being wired in or getting un-wired later, nobody importing the generated stylesheet, and init picking the wrong framework — plus what a working install actually looks like. The it-worked-yesterday section covers one component versus the whole app, and a list of subtler failures: a token printing as literal text, cascade layers deciding a fight, anyOfVariants losing by design, a variant prop styling without setting the attribute, a wrapped third-party component losing its styles, and variants nested inside base. Closes with where errors actually print, why strict is the highest-value setting on the page, and the failures that never print anything at all. - [Updates](https://new-website.salty-css.dev/docs/react/guides/updates): A guide to keeping a Salty CSS project current. Because every @salty-css/* package ships on the same version number, updating is one command rather than a per-package chore: salty-css update (alias up) bumps every Salty package in package.json together, optionally pinned to one version. Explains why bumping a single package by hand produces confusing failures rather than clear ones, documents the arguments and flags (version, --dir, --yes, --legacy-peer-deps), and notes that saltygen is a build artifact needing a fresh build after an install. Covers salty-css --version for reporting what is actually installed, points at GitHub Releases as the canonical changelog, and states the pre-1.0 framing plainly: minor APIs can still move between releases, so pin versions rather than floating on a caret. Distinguished from Migration, which is about moving onto Salty from something else rather than between Salty versions. - [Migration](https://new-website.salty-css.dev/docs/react/guides/migration): A guide to moving an existing codebase onto Salty CSS, split into what changes structurally for everyone and what each source library specifically maps to. The six universal changes: styles move into their own suffixed files, CSS text becomes camelCase style objects, values resolve at build time via a five-rung ladder from browser-tracked state to a plain style prop, the cascade becomes @layer rather than specificity, theming stops being a JavaScript object, and the requirement is a bundler rather than a framework. Notes what does not have to change — Salty coexists with whatever is already there — and two config options worth setting during a migration. Sorts sources into four categories that predict effort better than library names do: runtime CSS-in-JS, build-time CSS-in-JS, atomic utility-first, and preprocessors. Then per-source mapping tables and one worked translation each for styled-components 6.4, Stitches 1.2.8, Panda CSS 1.11, Linaria 8, Tailwind CSS 4.3 and Sass 1.102, naming the hardest part in each case — function interpolations, utils, output model, the system layer above the primitive, the unit of styling itself, and giving up cross-component selectors. Closes with a six-step sequence where every step ships. - [Framework agnostic APIs](https://new-website.salty-css.dev/docs/react/guides/framework-agnostic): A guide for using Salty CSS on a stack it does not ship wiring for. Almost everything written in a .css.ts file has no idea which framework you picked: tokens, templates, media queries, fonts, keyframes, global styles, helpers and class names are all TypeScript that runs in Node at build time and outputs text. The one genuine exception is styled, because a component factory has to hand back a component in the framework's own shape — so the actual requirement is much narrower than a framework list: Salty needs Vite or Webpack. Explains that the split is render time versus build time rather than React versus not, with a table of every API and its core import path, and notes that the @salty-css/react/* subpaths are straight re-exports of the core ones. Covers why the plugin's three jobs — a build-start hook, a loader hook and a watcher — are bundler jobs rather than framework jobs, the plugin wiring for Vite and Webpack, and the four setup steps. Then the authoring story with className: the full styling surface returned as a class string, the String-object caveat, the fact that defaultVariants is accepted but never applied, and the wrapper function that is also the natural seam for a component in your own framework. Closes with exactly what is given up without styled, all of which is component ergonomics rather than CSS. - [styled (reference)](https://new-website.salty-css.dev/docs/react/reference/styled): The complete API reference for styled() in Salty CSS. Documents the signature — a tag name or a component plus an options object, returning a typed component — and every option: base for styles every instance gets, variants as typed props, compoundVariants for AND combinations, anyOfVariants for OR combinations emitted inside :where() with zero specificity, defaultVariants, defaultProps, element for swapping the rendered tag, passProps for forwarding variant props to the element, className for a stable extra class, displayName, and priority for choosing the cascade layer. Also documents the props the rendered component accepts including className, style, as, css-* and ref forwarding; the css-* prop token mechanism and its camelCase to dash-case to CSS-variable naming chain; what happens when a component is wrapped, including the automatic and accumulating layer bump and outer-wins variant collisions; and the four compiler requirements — recognized filename suffix, top-level export, something importing it, and the file being safe to run in Node at build time. - [className (reference)](https://new-website.salty-css.dev/docs/react/reference/class-name): The complete API reference for className() in Salty CSS. Documents the signature — the same options type styled takes, returning a string-coercible ClassNameFunction with a .variant() method, a .generator and an .isClassName flag. Covers every option that has an effect: base, variants, compoundVariants, anyOfVariants emitted inside :where() with zero specificity, defaultVariants which is accepted but never applied, className for a stable extra class, displayName, and priority — including the two consequences that matter more here than on styled, namely that a class always starts at layer 0 because nothing auto-bumps it, and that a class placed on a component lands in the same layer so source order decides the winner. Documents the options with no effect (element, passProps, defaultProps and the as prop), the returned value and the fact that it is a String object rather than a primitive, the selectors each feature generates, the five-character hash derived from the style object alone, hash interpolation for targeting by identity, the four things className deliberately does not do, and the four compiler requirements. - [CSS reset (reference)](https://new-website.salty-css.dev/docs/react/reference/css-reset): Reference for the CSS reset Salty CSS applies by default. Covers what the reset addresses — box model, spacing, typography baseline, media, text flow, and interactive and form elements — and the deliberate scope, which is closer to sane modern defaults than a nuke-everything reset. Documents where the reset sits in the cascade: it is emitted into the reset layer near the bottom of the order, so everything you write lands in a higher layer and overriding any of it never needs !important. Documents the reset option in salty.config.ts with its three values (the built-in default, none for bringing your own, or a custom CSS object that replaces the built-in entirely rather than merging), and includes the complete source of saltyReset as it ships. - [CLI (reference)](https://new-website.salty-css.dev/docs/react/reference/cli): The complete CLI reference for Salty CSS. The binary ships inside @salty-css/core under four names and requires Node 22 or newer. Four commands: init detects the project type, installs matching packages, writes salty.config.ts and .saltyrc.json, edits the bundler config and runs a first build; generate scaffolds a component file with a compiler-readable suffix, optionally splitting into a styled definition plus a React wrapper with -r; build compiles the project CSS with --watch and --mode options; and update bumps every @salty-css/* package together. Documents that every path resolves against the current working directory and .saltyrc.json is read from there without an upward walk, that Prettier formats written files when present, and that nothing overwrites an existing file which is what makes init safe to re-run. Covers framework detection versus integration detection as two separate passes, the five integrations and what each edits, what gets installed and why versions are pinned in lockstep, the stylesheet-import search path, the incremental versus full rebuild split in watch mode, the --version output to paste into bug reports, and the three CI behaviours that need flags. - [Recipe · Decouple a Heading's Tag From Its Looks](https://new-website.salty-css.dev/recipes/react/polymorphic-heading): A Heading styled component whose default tag is

, with an `as` prop that swaps the element per call site — typed, no runtime cost. - [Source on GitHub](https://github.com/margarita-form/salty-css): Source code, issues and releases. - [Community Discord](https://discord.gg/R6kr4KxMhP): Get support and chat with the community. - [@salty-css/core on npm](https://www.npmjs.com/package/@salty-css/core): Published packages.