React SDK — @sorb/leaf

Leaf is the foliage rendered in your running app. Add one provider and your tokens flow through as CSS custom properties — live-swappable, no rebuild.

Not on React? The same package exports sorbInit, a framework-free injector, plus target adapters for Mantine, MUI, Tailwind v4, shadcn/ui, PrimeVue and Angular Material. See the @sorb/leaf reference.

Install

npm install @sorb/leaf

Wrap your app

SorbProvider takes one required prop, config. It needs at least a namespace and the committed tokens object your build generates (see Getting started). Import the generated variables.css too; the provider only overrides those variables during a preview, it does not create them.

import { SorbProvider, PreviewBanner } from "@sorb/leaf";
import { tokens } from "./tokens/generated/tokens";
import "./tokens/generated/variables.css";

const sorbConfig = {
  namespace: "my-app",
  tokens,
  preview: {
    enabled: import.meta.env.MODE !== "production",
    origin: "http://localhost:7777",
  },
};

export default function App() {
  return (
    <SorbProvider config={sorbConfig}>
      <YourApp />
      <PreviewBanner />
    </SorbProvider>
  );
}

Rendering <SorbProvider> without config throws Cannot read properties of undefined (reading 'tokens') at mount. The committed tokens are applied as CSS custom properties on :root; during a preview the proposed values replace them. Reference them the usual way, always with a fallback:

.button-primary {
  background: var(--button-primary-bg-default, #f26722);
}

Because the values are CSS variables, a token change re-skins the component without touching the component or triggering a rebuild.

Preview sessions

When the Figma plugin opens a preview session, Leaf receives the proposed values over the bridge and applies them live. Preview mode is off by default and accepts previews only from bridge origins you allowlist — a change proposed in Figma shows up in your real component, but nothing writes to your source.

Tailwind v4

Register @sorb/seed's sorb/tailwind-theme format in your sd.config.js and it emits a tailwind-theme.css file: one @theme inline entry per resolved token, each value a var(--token) reference into variables.css — so Tailwind utilities (bg-action-primary, rounded-button, border-border-default, …) resolve through the exact CSS vars a preview swaps at runtime, with zero Tailwind-specific bridge code.

/* your entry CSS, in this order */
@import "tailwindcss";
@import "./tokens/generated/variables.css";       /* Sorb tokens — the bridge swaps these live */
@import "./tokens/generated/tailwind-theme.css";  /* maps them into the Tailwind v4 theme */

Mapping: color tokens → --color-* (bg-/text-/border-), radius.*/button.radius → --radius-* (rounded-*), space.* → --spacing-*, font.size.* → --text-*, font.weight.* → --font-weight-*. See the @sorb/seed formats table for how to register the format, and its Tailwind v3 sibling (sorb/tailwind-v3-preset, consumed as presets: [require('./tailwind-sorb-preset.cjs')]) if you're not yet on v4.

Verify before merge

Once a change looks right, Sorb checks it against your live components' tier/type bindings before you merge.

Verified = checked against your live components' tier/type bindings before merge — not a visual or accessibility audit.

Next

  • @sorb/leaf reference — every export, grouped: hooks, dark mode, sorbInit, target adapters, the legacy map, security, diagnostics.
  • The bridge — the sorb dev server Leaf talks to.
  • Tokens & taxonomy — how the values get resolved and bound.

Works with Figma. Not affiliated with, or endorsed by, Figma. Figma is a trademark of Figma, Inc.