Docs

The Openpane kit

One line gives a pane Openpane's look in light and dark mode, and the libraries AI reaches for: Tailwind and daisyUI, charts, diagrams and icons. Openpane serves them itself.

Add it

In an HTML or Markdown pane, the kit's script tag goes first. In a React pane, import it.

HTMLa chart, a card and a button
<script src="/vendor/kit.js"></script>
<main class="mx-auto max-w-2xl space-y-4 p-4">
  <h1 class="text-2xl font-bold">Sign-ups</h1>
  <div class="card border border-base-300 bg-base-100">
    <div class="card-body">
      <div class="h-64"><canvas id="days"></canvas></div>
    </div>
  </div>
  <button class="btn btn-primary"><i data-lucide="send"></i> Send</button>
</main>
<script>
  openpane.chart("#days", {
    type: "bar",
    data: {
      labels: ["Mon", "Tue", "Wed", "Thu", "Fri"],
      datasets: [{ label: "Sign-ups", data: [180, 260, 240, 300, 224] }],
    },
    options: { maintainAspectRatio: false },
  });
</script>
Markdown
<script src="/vendor/kit.js"></script>

# Release notes

Panes now follow your device's **light or dark mode**.
ReactJSX
import kit from "/vendor/kit.js";

function App() {
  const canvas = useRef(null);
  useEffect(() => {
    const made = kit.chart(canvas.current, {
      type: "line",
      data: { labels: ["Mon", "Tue", "Wed"], datasets: [{ label: "Visits", data: [3, 5, 4] }] },
      options: { maintainAspectRatio: false },
    });
    return () => { made.then((chart) => chart.destroy()); };
  }, []);
  return (
    <main className="mx-auto max-w-2xl p-4">
      <div className="h-64"><canvas ref={canvas}></canvas></div>
    </main>
  );
}

Panes without the kit stay as they are: on a white sheet, with whatever look their own CSS gives them.

Openpane's look

  • Tailwind CSS utility classes and daisyUI components: btn, card, badge, alert, stats, table, tabs and the rest.
  • The openpane theme: Geist, one ink and stone, light or dark with the viewer's device. To keep one mode, set data-theme="openpane-light" or "openpane-dark" on <html>; any other daisyUI theme works too.
  • Theme colours that work in both modes: bg-base-200 for the page, bg-base-100 for cards, text-base-content (and /70 for muted text), border-base-300, btn-primary for the main action, badge-accent for the live mark.
  • The prose class sets long text: headings, lists, quotes, tables and code. Markdown panes get it already.

Charts

openpane.chart(canvas, config) draws a Chart.js chart and returns a promise of it. Give the canvas a box with a height, and set maintainAspectRatio: false.

  • Series you leave uncoloured take Openpane's palette: eight colours in a fixed order, checked for colour-blind readers and for contrast in light and dark mode.
  • Charts use Openpane's type and theme colours, show a legend from two series on, and redraw when the mode changes.
  • openpane.colors() gives the palette for the current mode, and openpane.load("chart") gives Chart.js itself.

Diagrams

Put Mermaid source in a mermaid block. Top-down flows read best on a phone.

HTML
<pre class="mermaid">
flowchart TD
  A[Claude asks] --> B[Your live page]
  B -->|you tap| C[Claude carries on]
</pre>

Icons

Any Lucide icon, by name. Icons take the size of the text around them, or a size class.

HTML
<i data-lucide="circle-check"></i> Done
<i data-lucide="send" class="size-6"></i>

Live panes

With Claude Code's Openpane plugin, each chat gets a live pane: a pane of your own where Claude's questions, its last message and its task list show up, and where it can build something for you to click. Claude publishes to it with create_pane and the chat's live id, and you watch it change as Claude works.

  • <openpane-live></openpane-live> marks where the questions, the last message and the tasks go. Without it they appear at the top when something waits for you.
  • openpane.send(value) sends Claude text, or data it gets as JSON, and returns a promise. It reaches Claude right away if Claude is waiting, or else when its turn ends.
  • Only the pane's owner, signed in, can send, and only right after a real tap or key press in the pane: a pane's own code can't send by itself.
  • openpane.onLive(fn) hands you the live state, to draw it your own way.
HTMLa button that sends
<script src="/vendor/kit.js"></script>
<button class="btn btn-primary" id="ship">Ship it</button>
<openpane-live></openpane-live>
<script>
  document.getElementById("ship").addEventListener("click", async () => {
    await openpane.send({ decision: "ship" });
  });
</script>

How to build a good pane

AI tools connected to Openpane get these rules with its MCP server, and Claude Code's plugin brings them as a skill.

  1. Load the kit first, and build with its classes rather than long CSS of your own.
  2. Phone first: one column, more on wider screens, tap targets of at least 44 px, and no sideways scrolling (wide tables go in overflow-x-auto).
  3. Theme colours only, never fixed white, black or grey, so the pane works in dark mode. A status colour always comes with a word or an icon.
  4. Leave chart colours to the kit. One y-axis per chart; past eight series, group the rest as "Other".
  5. Top-down diagrams with short labels.
  6. When a choice is visual, make a pane for each option and ask with ask_in_pane.
  7. Real content in short, plain words, and never a secret such as an API key.

What's inside

All open source, pinned, and served from Openpane's own domain. A pane loads only what it uses.

LibraryVersionLicenceLoaded
Tailwind CSS (browser build)4.3.3MITalways
daisyUI5.7.50MITalways
Chart.js4.5.1MITwith a chart
Mermaid12.2.0MITwith a diagram
Lucide1.61.0ISCwith an icon
The Openpane kit: Openpane's look, charts, diagrams and icons for panes · Openpane docs