Brochure-style content editor with a 3D panel preview, per-panel completion tracking, and side flipping.
Default brand color scheme
0/6 sections complete0%
x
Leave empty
Installation
$Terminal
npx shadcn@latest add https://sdk-components.thesqd.com/r/panel-editor.jsonUsage
Define your panels (with side + label), then render the editor with controlled state.
TSImport
import {
PanelEditor,
type PanelDefinition,
} from "@/components/blocks/panel-editor";TSExample
import * as React from "react";
import {
PanelEditor,
type PanelDefinition,
} from "@/components/blocks/panel-editor";
const panels: PanelDefinition[] = [
{ key: "out-1", label: "Panel 1", side: "outside" },
{ key: "out-2", label: "Panel 2", side: "outside" },
{ key: "out-3", label: "Panel 3", side: "outside" },
{ key: "in-1", label: "Panel 4", side: "inside" },
{ key: "in-2", label: "Panel 5", side: "inside" },
{ key: "in-3", label: "Panel 6", side: "inside" },
];
export function Example() {
const [values, setValues] = React.useState<Record<string, string>>({});
return (
<PanelEditor
label="Tri-fold brochure"
caption="Default brand color scheme"
required
foldType="tri_fold"
panels={panels}
value={values}
onChange={setValues}
/>
);
}Composition
Anatomy of the panel editor.
PanelEditor
├── Header (label / description / required indicator)
├── 3D fold preview (tri_fold | bi_fold | no_fold)
├── Side toggle (outside / inside, or front / back)
└── Per-panel content cards (one per PanelDefinition)Tri-fold (brand)
Six panels — three outside, three inside. Default brand color scheme.
Default brand color scheme
0/6 sections complete0%
x
Leave empty
Tri-fold (coral)
Same shape, alternate color scheme.
0/6 sections complete0%
x
Leave empty
Tri-fold (custom colors)
Pass `customColors` — an array of `{ background }` objects — to set per-panel colors directly. Each entry is applied to the corresponding panel; mix in `{ className }` if you'd rather use Tailwind utilities.
Per-panel colors via `customColors`.
0/6 sections complete0%
x
Leave empty
With dictation
`editor="dictation"` adds a mic button next to the active panel; the Web Speech API streams transcribed text into the active panel.
Click the mic in any panel and start talking.
0/6 sections complete0%
x
Leave empty
With rich-text editor
`editor="rich-text"` swaps the textarea for a `<RichTextEditor>` so authors can format copy inline (bold, italics, lists, links).
Each panel hosts a full RichTextEditor.
0/6 sections complete0%
x
Leave empty
Tri-fold (flat / 2D)
Pass `flat` to disable the 3D fold rotation — panels render as a flat 2D strip.
Same editor, no 3D fold rotation.
0/6 sections complete0%
x
Leave empty
Error state
Pass `errorMessage` to flag unfilled panels — the editor shakes (transitions-dev error-state-shake) and the message fades in below. Click Validate to trigger it.
Click Validate with unfilled panels to trigger the error.
0/6 sections complete0%
x
Leave empty
Bi-fold
Four panels — two outside, two inside.
0/4 sections complete0%
x
Leave empty
No fold (single sheet)
Front/back only. Flip swaps between the two faces.
0/2 sections complete0%
x
Leave empty
API Reference
Props for the PanelEditor block and the PanelDefinition entries.
PanelEditor
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | Field label rendered above the editor. |
caption | string | — | Sub-text under the label. |
required | boolean | false | Renders a required indicator. |
foldType | "tri_fold" | "bi_fold" | "no_fold" | — | Drives the 3D preview geometry and side vocabulary. |
panels | PanelDefinition[] | — | Panels rendered in display order. |
value | Record<string, string> | — | Per-panel content keyed by `PanelDefinition.key`. Panels marked "leave empty" store the exported `PANEL_LEFT_EMPTY` sentinel so validation/persistence see the decision — strip it to "" when shaping the final payload. |
onChange | (next: Record<string, string>) => void | — | Fired whenever any panel content changes. |
colorScheme | "brand" | "coral" | "rainbow" | "violet" | "pink" | "brand" | Color palette for the panel headers. |
flat | boolean | false | Render the panels flat (2D) — disables the 3D fold rotation. |
PanelDefinition
| Prop | Type | Default | Description |
|---|---|---|---|
key | string | — | Stable identifier — also the value-map key. |
label | string | — | Panel header label. |
side | "outside" | "inside" | "front" | "back" | — | Which face the panel belongs to (use front/back for `no_fold`). |