---
title: Playground
sidebarTitle: Playground
description: Build and preview Prefab components interactively in your browser.
icon: play
mode: wide
---

export const PlaygroundFrame = () => {
  const ref = React.useRef(null);
  const [src, setSrc] = React.useState(null);

  React.useEffect(function () {
    document.documentElement.setAttribute("data-page-mode", "wide");
    var isLocal = location.hostname === "localhost" || location.hostname === "127.0.0.1";
    var url = isLocal
      ? "/playground.html"
      : "https://cdn.jsdelivr.net/npm/@prefecthq/prefab-ui@latest/dist/playground.html";
    fetch(url).then(function(r) { return r.text(); }).then(function(html) {
      var blob = new Blob([html], { type: "text/html" });
      setSrc(URL.createObjectURL(blob));
    });
    return function () {
      document.documentElement.removeAttribute("data-page-mode");
    };
  }, []);

  React.useEffect(function () {
    if (!src) return;
    function onMessage(e) {
      if (!e.data) return;
      if (e.data.type === "pg-ready") {
        var hash = window.location.hash.slice(1);
        if (!hash) return;
        var params = new URLSearchParams(hash);
        var encoded = params.get("code");
        var theme = params.get("theme");
        if (ref.current && ref.current.contentWindow && (encoded || theme)) {
          ref.current.contentWindow.postMessage({
            type: "pg-init-code",
            encoded: encoded || "",
            theme: theme || "",
          }, "*");
        }
      } else if (e.data.type === "pg-code-changed" || e.data.type === "pg-theme-changed") {
        window.history.replaceState(null, "", "#" + e.data.hash);
      }
    }
    window.addEventListener("message", onMessage);
    return function () { window.removeEventListener("message", onMessage); };
  }, [src]);

  if (!src) return null;
  return <iframe ref={ref} src={src} style={{ width: "100%", height: "max(800px, 80vh)", border: "none" }} sandbox="allow-scripts allow-same-origin" />;
};

<PlaygroundFrame />

---

## Render Target

The playground renders whichever thing was created last: a standalone component or a `PrefabApp`. Create a `PrefabApp` after your components and it becomes the output, bringing its theme and mode along.

For explicit control, define `main()` and return whatever you want rendered:

```python
from prefab_ui.app import PrefabApp
from prefab_ui.themes import Presentation
from prefab_ui.components import Column, Heading

def main():
    with Column() as view:
        Heading("Dashboard")
    return PrefabApp(view=view, theme=Presentation(accent="cyan"))
```

`main()` always takes priority when your code creates multiple components or apps.

## Themes

Themes from `PrefabApp` apply in the playground the same as in production. The toolbar's theme picker overrides the code-defined theme when active; selecting "Code" restores it.

See the [themes docs](/styling/themes) for `Basic`, `Dashboard`, `Presentation`, and custom themes.
