Version 0.2.0 released! Check out the release notes from GitHub Releases

Styled, className, Tokens, and Globals — Four Concepts for Authoring Island-Friendly Components

Salty CSS Basics for Astro

The two primitives you'll reach for most are styled and className. styled produces a typed component — variants become typed props, the element is configurable, and the whole thing composes. className produces a class string you apply to markup you already control. Start with styled; switch to className when the component wrapper gets in the way.

styled

The styled function creates a typed component from an HTML tag or another component. Variants become typed props; the element, class name, and display name are all configurable.

// /components/my-component.css.ts
import { styled } from "@salty-css/astro/styled";

export const Component = styled("div", {
  className: "wrapper", // Define optional custom class name that will be included for this component
  element: "section", // Override the html element that will be rendered for this component
  base: {
    display: "flex",
    padding: "1rem",
    // Add your CSS-in-JS base styles here
  },
});

className

className gives you the same styling features — variants, nesting, tokens, media queries — but returns a class string instead of a component. It can't wrap an element and can't extend other Salty components. Reach for it when you're working with markup you already control, or when a component wrapper would be one layer too many.

// /components/my-class.css.ts
import { className } from "@salty-css/astro/class-name";

export const myClass = className({
  className: "wrapper", // Define optional custom class name that will be included to the scope
  base: {
    display: "flex",
    padding: "1rem",
    // Add your CSS-in-JS base styles here
  },
});

Usage example:

---
// src/pages/index.astro
import { myClass } from "../styles/my-class.css";
---

<div class={myClass}>Hello world</div>

Global Styles

Global styles target bare HTML selectors — anything not scoped to a single component. Use them for resets, base typography, anchor colors, or anything else you'd otherwise stuff into a top-level CSS file. Define them in a .css.ts file and export the result so the build picks them up:

// /styles/global.css.ts
import { defineGlobalStyles } from "@salty-css/core/factories";

export const globalStyles = defineGlobalStyles({
  html: {
    scrollBehavior: "smooth",
    scrollPaddingTop: "5vh",
  },
  body: {
    margin: 0,
    fontFamily: "var(--font-family-main, helvetica, sans-serif)",
    overflowY: "scroll",
  },
  a: {
    color: "currentcolor",
  },
  // Nested objects work — selectors compose with the parent.
  "pre:has(code)": {
    background: "{theme.terminalBackground}",
    overflow: "auto",
    border: "1px solid {theme.altBackground}",
    "& pre": {
      padding: "0 1em",
      border: "none",
    },
  },
});

Token references ({theme.terminalBackground}) and nested selectors (& pre) work here exactly as they do inside styled and className. The same options are also accepted by defineConfig({ global }) — pick whichever fits your project layout.

For the built-in reset and how to opt out of it, see defineConfig.reset.

Static design tokens

CSS variables create design tokens that can be reused throughout your application. Salty CSS supports static, responsive (breakpoint-aware), and conditional (theme-aware) tokens — this section covers the static case; for the rest, see Variables and Theming.

// /styles/variables.css.ts
import { defineVariables } from "@salty-css/core/factories";

export default defineVariables({
  colors: {
    dark: "#111",
    light: "#fefefe",
    brand: {
      main: "#0070f3",
      highlight: "#ff4081",
    },
  },
  spacing: {
    small: "8px",
    medium: "16px",
    large: "32px",
  },
  fontFamily: {
    heading: "Arial, sans-serif",
    body: "Georgia, serif",
  },
});

Reference tokens with {path.to.token} syntax from any style object:

styled("span", {
  base: {
    fontFamily: "{fontFamily.heading}",
    color: "{colors.brand.main}",
    padding: "{spacing.medium}",
  },
});

Token paths are validated at build time — typos surface as compiler output rather than as silent fallbacks in the browser.

Where to go next

  • Variables — responsive and conditional token scopes.
  • Theming — dark mode in a few lines.
  • Fonts — register web fonts with defineFont.
  • Imports — pull in external CSS.
  • Templates — bundle reusable style patterns.