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.
<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><script src="/vendor/kit.js"></script>
# Release notes
Panes now follow your device's **light or dark mode**.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,tabsand the rest. - The
openpanetheme: Geist, one ink and stone, light or dark with the viewer's device. To keep one mode, setdata-theme="openpane-light"or"openpane-dark"on<html>; any other daisyUI theme works too. - Theme colours that work in both modes:
bg-base-200for the page,bg-base-100for cards,text-base-content(and/70for muted text),border-base-300,btn-primaryfor the main action,badge-accentfor the live mark. - The
proseclass 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, andopenpane.load("chart")gives Chart.js itself.
Diagrams
Put Mermaid source in a mermaid block. Top-down flows read best on a phone.
<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.
<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.
<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.
- Load the kit first, and build with its classes rather than long CSS of your own.
- 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). - 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.
- Leave chart colours to the kit. One y-axis per chart; past eight series, group the rest as "Other".
- Top-down diagrams with short labels.
- When a choice is visual, make a pane for each option and ask with
ask_in_pane. - 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.
| Library | Version | Licence | Loaded |
|---|---|---|---|
| Tailwind CSS (browser build) | 4.3.3 | MIT | always |
| daisyUI | 5.7.50 | MIT | always |
| Chart.js | 4.5.1 | MIT | with a chart |
| Mermaid | 12.2.0 | MIT | with a diagram |
| Lucide | 1.61.0 | ISC | with an icon |