Playground
Try every prop, live
This is the real <MultiWidget /> with a small budget dataset. Flip props on the left, drill into the widget on the right, and copy the matching code below.
November
Budget
$253 tracked
Categories
Generated code
import { useState } from "react";
import { MultiWidget, type MultiWidgetSlide } from "@/components/multi-widget";
const CATS = [/* your categories */];
export function BudgetWidget() {
const [catId, setCatId] = useState<string | null>(null);
const [txId, setTxId] = useState<string | null>(null);
const cat = CATS.find((c) => c.id === catId) ?? null;
const tx = cat?.txs.find((t) => t.id === txId) ?? null;
const onPrev = () => {
if (txId) setTxId(null);
else if (catId) setCatId(null);
};
const slides: MultiWidgetSlide[] = [
{
key: "overview",
variant: "dark",
hideOnNarrow: true,
content: <Overview />,
},
{
key: "cats",
tabTitle: "Categories",
content: <CategoryList onPick={setCatId} active={catId} />,
},
...(cat ? [{
key: `txs-${cat.id}`,
tabTitle: cat.name,
onBack: () => setCatId(null),
content: <TxList tx={cat.txs} onPick={setTxId} active={txId} />,
}] : []),
...(tx ? [{
key: `detail-${tx.id}`,
tabTitle: "Detail",
size: "2/3",
onBack: () => setTxId(null),
onEdit: () => {},
content: <TxDetail tx={tx} />,
}] : []),
];
return (
<MultiWidget
eyebrow="Playground"
title="Budget"
slides={slides}
hasSelection={catId !== null}
onPrev={onPrev}
/>
);
}
Drop this into a route or component. The two useState hooks own the selection — the widget itself is stateless about the hierarchy.