{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "vertical-tabs",
  "type": "registry:ui",
  "title": "Vertical tabs",
  "description": "Vertical tabs with a 180px tab list on the left and the active panel on the right, using tab and tabpanel roles. Stacks on mobile. Built for settings screens.",
  "dependencies": [],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/ui/vertical-tabs.tsx",
      "type": "registry:ui",
      "target": "components/ui/vertical-tabs.tsx",
      "content": "\"use client\"\nimport * as React from \"react\"\nimport { cn } from \"@/lib/utils\"\n\n/** A left-hand tab list with the active panel beside it, for settings pages. */\ntype VerticalTab = { id: string; label: string; content: React.ReactNode }\n\ntype VerticalTabsProps = {\n  /** Tabs in order; the first is selected by default. Defaults to Lumen's workspace settings. */\n  tabs?: VerticalTab[]\n  /** Controlled selected tab id. */\n  value?: string\n  onChange?: (id: string) => void\n  className?: string\n}\n\nfunction Panel({ title, rows, note }: { title: string; rows: [string, string][]; note: string }) {\n  return (\n    <div className=\"rounded-xl border border-border bg-surface p-4\">\n      <h3 className=\"text-sm font-medium text-fg\">{title}</h3>\n      <dl className=\"mt-3 divide-y divide-border text-sm\">\n        {rows.map(([k, v]) => (\n          <div key={k} className=\"flex items-baseline justify-between gap-4 py-2\">\n            <dt className=\"text-fg-muted\">{k}</dt>\n            <dd className=\"font-medium tabular-nums text-fg\">{v}</dd>\n          </div>\n        ))}\n      </dl>\n      <p className=\"mt-3 text-xs leading-[1.6] text-fg-muted\">{note}</p>\n    </div>\n  )\n}\n\nconst SAMPLE_TABS: VerticalTab[] = [\n  {\n    id: \"general\",\n    label: \"General\",\n    content: (\n      <Panel\n        title=\"Workspace\"\n        rows={[\n          [\"Name\", \"Northwind\"],\n          [\"URL\", \"lumen.app/northwind\"],\n          [\"Time zone\", \"America/Los_Angeles\"],\n          [\"Fiscal year starts\", \"January\"],\n        ]}\n        note=\"Changing the URL redirects old links for 90 days.\"\n      />\n    ),\n  },\n  {\n    id: \"billing\",\n    label: \"Billing\",\n    content: (\n      <Panel\n        title=\"Plan and invoices\"\n        rows={[\n          [\"Plan\", \"Scale\"],\n          [\"Price\", \"$490 / month\"],\n          [\"Next invoice\", \"Apr 1, 2026\"],\n          [\"Payment method\", \"Visa ending 4421\"],\n        ]}\n        note=\"Invoices are emailed to billing@northwind.com and kept here for seven years.\"\n      />\n    ),\n  },\n  {\n    id: \"members\",\n    label: \"Members\",\n    content: (\n      <Panel\n        title=\"People\"\n        rows={[\n          [\"Seats used\", \"18 of 25\"],\n          [\"Owners\", \"Maya Chen\"],\n          [\"Admins\", \"Priya Raman, Sam Lowe\"],\n          [\"Pending invites\", \"2\"],\n        ]}\n        note=\"Members can see every invoice; only admins can send or void them.\"\n      />\n    ),\n  },\n  {\n    id: \"api\",\n    label: \"API keys\",\n    content: (\n      <Panel\n        title=\"Keys\"\n        rows={[\n          [\"Production\", \"lum_live_…8f21\"],\n          [\"Last used\", \"2 minutes ago\"],\n          [\"Sandbox\", \"lum_test_…c04d\"],\n          [\"Rate limit\", \"1,000 requests / min\"],\n        ]}\n        note=\"Rotate a key and the old one keeps working for 24 hours.\"\n      />\n    ),\n  },\n]\n\nfunction VerticalTabs({ tabs = SAMPLE_TABS, value, onChange, className }: VerticalTabsProps) {\n  const [internal, setInternal] = React.useState(tabs[0]?.id)\n  const current = value ?? internal\n  const active = tabs.find((t) => t.id === current) ?? tabs[0]\n  return (\n    <div data-slot=\"vertical-tabs\" className={cn(\"grid w-full gap-4 md:grid-cols-[180px_1fr]\", className)}>\n      <div role=\"tablist\" aria-orientation=\"vertical\" className=\"flex flex-col gap-1\">\n        {tabs.map((t) => (\n          <button\n            key={t.id}\n            type=\"button\"\n            role=\"tab\"\n            aria-selected={t.id === current}\n            className={cn(\n              \"h-9 rounded-lg px-3 text-left text-sm outline-none focus-visible:ring-2 focus-visible:ring-accent\",\n              t.id === current ? \"bg-sunken text-fg\" : \"text-fg-muted hover:text-fg\"\n            )}\n            onClick={() => {\n              if (value === undefined) setInternal(t.id)\n              onChange?.(t.id)\n            }}\n          >\n            {t.label}\n          </button>\n        ))}\n      </div>\n      <div role=\"tabpanel\" className=\"min-w-0\">{active?.content}</div>\n    </div>\n  )\n}\nexport { VerticalTabs }\nexport type { VerticalTabsProps, VerticalTab }\n"
    }
  ]
}
