{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "onboarding-5",
  "title": "Invite Your Team Step",
  "description": "Invite-teammates onboarding step marked 3 of 4, with add and remove email rows, a role select per invite, and skip or send actions.",
  "dependencies": [
    "@base-ui/react"
  ],
  "registryDependencies": [
    "button",
    "input",
    "select",
    "separator"
  ],
  "files": [
    {
      "path": "registry/blocks/onboarding/5/onboarding-block.tsx",
      "content": "\"use client\"\n\nimport { useState } from \"react\"\nimport { Button } from \"@/components/ui/button\"\nimport { Input } from \"@/components/ui/input\"\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n  SelectValue,\n} from \"@/components/ui/select\"\nimport { Separator } from \"@/components/ui/separator\"\nimport { IconPlaceholder } from \"@/components/icons/icon-placeholder\"\n\ntype Invite = { id: number; email: string; role: string }\n\nlet counter = 3\n\nexport default function OnboardingBlock() {\n  const [invites, setInvites] = useState<Invite[]>([\n    { id: 1, email: \"\", role: \"Member\" },\n    { id: 2, email: \"\", role: \"Member\" },\n  ])\n\n  const addRow = () =>\n    setInvites((prev) => [\n      ...prev,\n      { id: ++counter, email: \"\", role: \"Member\" },\n    ])\n  const removeRow = (id: number) =>\n    setInvites((prev) => prev.filter((invite) => invite.id !== id))\n  const update = (id: number, patch: Partial<Invite>) =>\n    setInvites((prev) =>\n      prev.map((invite) =>\n        invite.id === id ? { ...invite, ...patch } : invite\n      )\n    )\n\n  return (\n    <section className=\"flex min-h-svh w-full items-center justify-center bg-muted/30 px-6 py-16 text-foreground\">\n      <div className=\"w-full max-w-lg rounded-xl border border-border bg-background p-8\">\n        <div className=\"inline-flex w-fit items-center gap-2 text-xs font-medium tracking-widest text-muted-foreground uppercase\">\n          <span>Step 3 of 4</span>\n          <Separator className=\"flex-1\" />\n        </div>\n        <h1 className=\"mt-4 font-heading text-2xl font-bold tracking-tight\">\n          Invite your team\n        </h1>\n        <p className=\"mt-2 text-sm text-muted-foreground\">\n          Acme is better together. Add teammates now, or skip and invite them\n          later.\n        </p>\n\n        <div className=\"mt-6 flex flex-col gap-3\">\n          {invites.map((invite) => (\n            <div key={invite.id} className=\"flex items-center gap-2\">\n              <div className=\"relative flex-1\">\n                <IconPlaceholder\n                  lucide=\"Mail\"\n                  tabler=\"IconMail\"\n                  hugeicons=\"MailIcon\"\n                  phosphor=\"Envelope\"\n                  remixicon=\"RiMailLine\"\n                  className=\"pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground\"\n                  aria-hidden=\"true\"\n                />\n                <Input\n                  type=\"email\"\n                  value={invite.email}\n                  onChange={(event) =>\n                    update(invite.id, { email: event.target.value })\n                  }\n                  placeholder=\"name@company.com\"\n                  className=\"pl-8\"\n                  aria-label=\"Teammate email\"\n                />\n              </div>\n              <Select\n                value={invite.role}\n                onValueChange={(value) =>\n                  update(invite.id, { role: value as string })\n                }\n              >\n                <SelectTrigger className=\"w-28\" aria-label=\"Role\">\n                  <SelectValue />\n                </SelectTrigger>\n                <SelectContent>\n                  <SelectItem value=\"Admin\">Admin</SelectItem>\n                  <SelectItem value=\"Member\">Member</SelectItem>\n                  <SelectItem value=\"Viewer\">Viewer</SelectItem>\n                </SelectContent>\n              </Select>\n              <Button\n                variant=\"ghost\"\n                size=\"icon\"\n                aria-label=\"Remove invite\"\n                onClick={() => removeRow(invite.id)}\n                disabled={invites.length === 1}\n              >\n                <IconPlaceholder\n                  lucide=\"X\"\n                  tabler=\"IconX\"\n                  hugeicons=\"Cancel01Icon\"\n                  phosphor=\"X\"\n                  remixicon=\"RiCloseLine\"\n                  className=\"size-4\"\n                  aria-hidden=\"true\"\n                />\n              </Button>\n            </div>\n          ))}\n        </div>\n\n        <Button variant=\"outline\" size=\"sm\" className=\"mt-3\" onClick={addRow}>\n          <IconPlaceholder\n            lucide=\"Plus\"\n            tabler=\"IconPlus\"\n            hugeicons=\"Add01Icon\"\n            phosphor=\"Plus\"\n            remixicon=\"RiAddLine\"\n            data-icon=\"inline-start\"\n            aria-hidden=\"true\"\n          />\n          Add another\n        </Button>\n\n        <div className=\"mt-8 flex items-center justify-between\">\n          <Button variant=\"ghost\" render={<a href=\"#\" />} nativeButton={false}>\n            Skip for now\n          </Button>\n          <Button>Send invites</Button>\n        </div>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/blocks/onboarding-5.tsx"
    }
  ],
  "meta": {
    "height": "518px",
    "tier": "free"
  },
  "docs": "Requires a `base-*` style in components.json (the `shadcn init` default). Legacy `new-york`/`radix-*` styles install Radix primitives, which reject the `render` prop this block uses.",
  "categories": [
    "onboarding"
  ],
  "type": "registry:block"
}