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.