Skip to content
Data
Skill

/building-react-quill-canvases

Author the React + Quill implementation of a PostHog canvas: the single-component contract, the allowed imports, Quill (PostHog's design system) component and composition rules, theme-aware design tokens, loading skeletons, and the in-canvas date picker. Use after

From plugin
posthog-posthog
40k163 skills11 agents1 command3 MCP
Install
$ npx -y skills add posthog/posthog --skill building-react-quill-canvases --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/building-react-quill-canvases

Context preview

The summary Claude sees to decide when to auto-load this skill.

Author the React + Quill implementation of a PostHog canvas: the single-component contract, the allowed imports, Quill (PostHog's design system) component and composition rules, theme-aware design tokens, loading skeletons, and the in-canvas date picker. Use after

SKILL.md

building-react-quill-canvases.SKILL.md
name: building-react-quill-canvases
description: >
  Author the React + Quill implementation of a PostHog canvas: the single-component contract, the
  allowed imports, Quill (PostHog's design system) component and composition rules, theme-aware
  design tokens, loading skeletons, and the in-canvas date picker. Use after building-canvases has
  routed a canvas request to a React implementation — dashboards, data boards, forms, tools, or any
  canvas that should look native to PostHog.

Building React + Quill canvases

The whole application is one React/TSX file (`src/canvas.tsx` in the source project). It must `export default` a single React component that takes no props — the host mounts it. Do not import react-dom or call createRoot.

Start from the working scaffold in [references/starter-scaffold.md](references/starter-scaffold.md) on a first build: it already wires the date picker, theme tokens, per-query loading state (every card fills in independently as its own data lands), and correct typed-node result reading. Keep that wiring; replace the sample metrics and layout.

Imports

Use React, Quill, Recharts, Lucide, and Day.js for the standard application shell. The platform also admits ten optional libraries for specialized work. Read [references/platform-libraries.md](references/platform-libraries.md) before choosing one.

PostHog data comes through `import { ph } from "@posthog/canvas-sdk"` — a platform-provided module, so it needs no `dependencies` entry. The same object exists as the `window.ph` global (how existing canvases reach it); prefer the import in new code.

Other bare imports, dynamic `import()`, `require()`, `<script>` tags, and remote code fail validation. Direct network requests and external images, fonts, media, or frames require an exact HTTPS origin in `capabilities.network.origins`. They work only in the **published** canvas — the edit-mode preview blocks direct network access regardless of declaration. Stylesheets from declared origins are allowed; remote scripts remain blocked, so bundle code with the canvas.

Quill component rules

A PostHog data board must be built entirely from `@posthog/quill` components — never a native control or a styled `<div>` standing in for one:

  • Dropdown/picker → `Select` (never a native `<select>`); button → `Button` (never `<button>`);

text field → `Input`/`Textarea`; checkbox → `Checkbox`; label → `Label`.

  • Table → `Table` (`TableHeader` > `TableRow` > `TableHead`, then `TableBody` > `TableRow` > `TableCell`);

panel → `Card` (`CardHeader` + `CardTitle` + `CardContent`); pill → `Badge`; titles → `Heading`; body → `Text`.

  • The only non-Quill tags allowed are plain layout `<div>`s and `recharts` elements.
  • Quill is built on Base UI: compose compound parts (`Select` + `SelectTrigger`/`SelectContent`/`SelectItem`),

use controlled `value` + `onValueChange`, and swap a part's element with the `render` prop (e.g. `<PopoverTrigger render={<Button …/>} />`) instead of wrapping it.

  • Quill components are already themed — never restyle one with Tailwind classes or inline `style`;

use their `variant`/`size` props. Put layout utilities (`flex`, `grid`, `gap-4`, `p-4`) on your own wrapper `<div>`s.

  • Buttons: default to `variant="outline"`; `variant="primary"` for the one main action only.

Styling and theme

  • Give the canvas's outermost element `h-screen` (`height: 100vh`) so it fills the iframe viewport.

Do not use `h-full` there: a published canvas's artifact shell gives its `html`, `body`, and `#root` elements no explicit height, so a percentage root height collapses to content height. Nested elements may use `h-full` once their parent establishes a height.

  • Style with Tailwind utilities and Quill components; reserve inline `style` for genuinely dynamic

runtime values (fixed sizes use arbitrary-value utilities like `h-[280px]`).

  • Write specific interface copy. Never use lorem ipsum or placeholder labels in a finished canvas.
  • The canvas follows the user's PostHog theme; a `.dark` class on the document root flips at runtime.

Color only from the design-token utilities — surfaces `bg-background bg-card bg-muted bg-primary bg-success bg-warning bg-info bg-destructive`; text `text-foreground text-muted-foreground text-card-foreground`; borders `border-border`. Never a hardcoded hex or light-only color.

  • Status tokens invert the usual convention: the bare token (`bg-success`) is a pale background fill

and `-foreground` (`text-success-foreground`) is the strong readable color. Colored text or icons always use the `-foreground` utility; a filled pill pairs `bg-success text-success-foreground`. Prefer the Quill `Badge` (`variant="success"`/`"destructive"`) for deltas so you don't hand-pick.

  • `bg-secondary`, `text-secondary`, `bg-accent`, and `bg-popover` are not defined in the canvas — avoid them.
  • Never declare a CSS variable with a platform token name (`--background`, `--border`, `--card`,

`--chrome`, `--input`, `--muted`, `--primary`, `--fill-*`), in a stylesheet or a `<style>` block. Quill sets those on every element, so your value never applies and text can turn unreadable. Prefix your own variables (`--doc-muted`); validation rejects the collision with `platform_token_redeclared`.

  • recharts strokes/fills use token CSS variables (`stroke="var(--primary)"`, grid/axes in

`var(--border)`/`var(--muted-foreground)`).

  • Write Unicode glyphs (curly quotes, ellipsis, arrows, emoji) as literal characters in JSX —

`\uXXXX` escapes render verbatim in JSX text.

Loading, error, and empty states

Every data point renders a skeleton in its own `Card` while loading or refreshing: `SkeletonText` (matching `lines` and text-size `className`) for text/number values, `Skeleton` for blocks/charts.

Render progressively — each query owns its loading state. The chrome (heading, date picker, card frames with skeletons inside) renders immediately, every independent query fires concurrently on mo

Read more
Ships withposthog-posthog

:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.

Get the whole plugin

Other skills on posthog-posthog.