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/leafreference — every export, grouped: hooks, dark mode,sorbInit, target adapters, the legacy map, security, diagnostics.- The bridge — the
sorb devserver 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.