Integrations

React Integration

The React adapter gives you fully typed components that consume your design system tokens. Works with any React framework: Next.js, Remix, Vite, and more.

Installation

Install your design system package (replace @org/design-system with your actual package name):

Terminalbash
npm install @org/design-system

Import tokens in root layout

Import the CSS once at your app root. This injects all CSS custom properties (design tokens) into the document:

app/layout.tsxtsx
// app/layout.tsx
import '@org/design-system/css';   // injects CSS variables

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return <html><body>{children}</body></html>;
}

Import and use components

Import components from the /react sub-path:

components/MyPage.tsxtsx
import { Button, Badge } from '@org/design-system/react';

export function MyPage() {
  return (
    <div>
      <Badge variant="success">Live</Badge>
      <Button variant="primary" onClick={() => alert('clicked')}>
        Deploy now
      </Button>
    </div>
  );
}

TypeScript support

All components are fully typed, with no separate @types package needed. Prop types, variant unions, and event handlers are all inferred:

example.tsxtsx
import { Button } from '@org/design-system/react';
import type { ButtonProps } from '@org/design-system/react';

// TypeScript knows: variant is 'primary' | 'secondary' | 'ghost'
const props: ButtonProps = {
  variant: 'primary',
  size: 'md',
  onClick: (e) => console.log(e),
};

// This would be a compile-time error:
// <Button variant="invalid" />  // ❌ Type '"invalid"' is not assignable

Types are generated from your design system configuration at publish time, so they always reflect the exact variants and props available in your version.

Switching modes

To switch between light, dark, or any custom mode, set the data-theme attribute on any ancestor element. In React you can apply it to the <html> element via useEffect for document-wide mode switching, or scope it to any subtree to render two modes side-by-side.

components/ThemeToggle.tsxtsx
// Toggle dark mode on the document root
'use client';
import { useEffect, useState } from 'react';

export function ThemeToggle() {
  const [dark, setDark] = useState(false);

  useEffect(() => {
    document.documentElement.setAttribute('data-theme', dark ? 'dark' : 'light');
  }, [dark]);

  return (
    <button onClick={() => setDark((d) => !d)}>
      {dark ? 'Light mode' : 'Dark mode'}
    </button>
  );
}

Staying up to date

Every merge to main in Studio publishes a new versioned npm package automatically. Your app keeps its pinned version until you explicitly update. To pull in the latest release:

Terminalbash
npm update @org/design-system

Use a caret range in your package.json to automatically pick up non-breaking patch and minor releases:

package.jsonjson
{
  "dependencies": {
    "@org/design-system": "^1.0.0"
  }
}

Using tokens directly

Even when you're using React components, you can access your design token CSS variables directly in custom styles. This is useful for one-off layouts and page sections that aren't components in your design system. You get the same visual consistency without wrapping everything in a component.

components/HeroBanner.tsxtsx
// Use token CSS variables in inline styles or CSS Modules
export function HeroBanner() {
  return (
    <section style={{ background: 'var(--ds-color-surface-subtle)', padding: 'var(--ds-spacing-8)' }}>
      <h1 style={{ color: 'var(--ds-color-text-primary)' }}>Hello</h1>
    </section>
  );
}

Next steps

Using Vue? The Vue adapter works the same way.

Vue Integration →