# Theme Provider
Applies Creator's theme tokens as CSS variables for dynamic theming.

## Import/Installation

<Tabs items={[{ label: 'Package', value: 'package' }, { label: 'Registry', value: 'registry' }]}>
  <TabsContent value="package">
    ```tsx
    import { ThemeProvider, useTheme } from "@lottiefiles/creator-plugins-ui";
    ```
  </TabsContent>

  <TabsContent value="registry">
    ```bash
    npx shadcn@latest add @lottiefiles/theme-provider
    ```
  </TabsContent>
</Tabs>

## Dynamic theming

The theme provider lets you pass Creator's current theme styles, or your own custom themes, to automatically style your plugin.

## Preview

<iframe src="https://creator-plugins-ds.lottiefiles.com/?story=theme-provider--default&mode=preview" style={{ width: "100%", border: "1px solid rgba(128, 128, 128, 0.4)", borderRadius: "8px" }} height="456" title="Theme Provider component live preview" frameBorder="no" loading="lazy" />

## Usage

```tsx
<ThemeProvider tokens={tokens} themeName="default">
  <App />
</ThemeProvider>
```

You can pass any CSS variable as a token. See [Theming](/en/creator-plugins/ui-library/theming) for the full list of tokens the library consumes.

## Match Creator's current theme

To automatically match Creator's current theme, your plugin can read Creator's current theme tokens and pass them to `ThemeProvider`.

### Step 1: Add the head script

Add this `<script>` block inside `<head>` in your plugin's `index.html`. It catches theme tokens via `postMessage` before React mounts, eliminating an initial flash of default-themed content.

The `vite-ignore` attribute prevents Vite from stripping the inline script during production builds.

```html
<script vite-ignore>
  (() => {
    function onTheme(event) {
      const msg = event.data?.pluginMessage;
      if (!msg || msg.type !== "change:theme") return;
      const { tokens } = msg;
      if (tokens && typeof tokens === "object") {
        const root = document.documentElement;
        for (const [key, value] of Object.entries(tokens)) {
          root.style.setProperty(key, value);
        }
        document.body.setAttribute("data-theme-ready", "");
      }
      window.removeEventListener("message", onTheme);
    }
    window.addEventListener("message", onTheme);
    if (window.parent !== window) {
      window.parent.postMessage({ pluginMessage: { type: "ui-ready" } }, "*");
    }
  })();
</script>
```

### Step 2: Plugin sandbox (`plugin.ts`)

```ts
creator.ui.show({ width: 360, height: 500 });

// set the theme on plugin load
creator.ui.onMessage((msg) => {
  if (msg.type === "ui-ready") {
    const { tokens, themeName } = creator.ui.theme;
    creator.ui.postMessage({ type: "change:theme", tokens, themeName });
  }
});

// update the theme when Creator's theme changes
creator.on("change:theme", ({ tokens, themeName }) => {
  creator.ui.postMessage({ type: "change:theme", tokens, themeName });
});
```

### Step 3: Plugin UI (`app.tsx`)

```tsx
import { useState, useEffect } from "react";
import { ThemeProvider, Button } from "@lottiefiles/creator-plugins-ui";

function App() {
  const [tokens, setTokens] = useState<Record<string, string>>();
  const [themeName, setThemeName] = useState<string>();

  useEffect(() => {
    window.addEventListener("message", (e) => {
      const msg = e.data?.pluginMessage;
      if (msg?.type === "change:theme") {
        setTokens(msg.tokens);
        setThemeName(msg.themeName);
      }
    });
    parent.postMessage({ pluginMessage: { type: "ui-ready" } }, "*");
  }, []);

  return (
    <ThemeProvider tokens={tokens} themeName={themeName}>
      <Button>Themed Button</Button>
    </ThemeProvider>
  );
}
```

### How it works

The head script applies Creator's theme tokens instantly when the first `change:theme` message arrives — before React mounts. Once React boots, `ThemeProvider` takes over for any subsequent theme changes. The `data-theme-ready` attribute on `<body>` coordinates the handoff so `ThemeProvider` doesn't reset the head script's tokens on mount.

## Transparent background default

When `ThemeProvider` has no tokens (or tokens are cleared), it sets `--background` to `transparent`. This is intentional for Creator's iframe context — it lets the host page's background show through.

If you're using `ThemeProvider` outside of Creator's iframe, set `--background` explicitly in your tokens to avoid an invisible background.

## Props

<PropsTable
  props={[
  {
    name: "children",
    type: "ReactNode",
    required: true,
    description: "Content to render inside the theme context.",
  },
  {
    name: "tokens",
    type: "Record<string, string>",
    description: "Current theme tokens (CSS variable name → value).",
  },
  {
    name: "themeName",
    type: "string",
    description: "Optional name of the active theme. Available via the `useTheme()` hook.",
  },
]}
/>
