{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "auth-3",
  "title": "Sign-Up With Plan Sidebar",
  "description": "Sign-up form paired with a plan sidebar listing Free, Pro, and Team tiers, first and last name fields, and a terms checkbox gating submit.",
  "dependencies": [
    "zod",
    "@base-ui/react"
  ],
  "registryDependencies": [
    "badge",
    "button",
    "card",
    "checkbox",
    "field",
    "input",
    "label",
    "separator",
    "sonner"
  ],
  "files": [
    {
      "path": "registry/blocks/auth/3/auth-block.tsx",
      "content": "\"use client\"\n\nimport { useState } from \"react\"\nimport { toast } from \"sonner\"\nimport { z } from \"zod\"\n\nimport { Badge } from \"@/components/ui/badge\"\nimport { Button } from \"@/components/ui/button\"\nimport {\n  CardContent,\n  CardDescription,\n  CardFooter,\n  CardHeader,\n  CardTitle,\n} from \"@/components/ui/card\"\nimport { Checkbox } from \"@/components/ui/checkbox\"\nimport {\n  Field,\n  FieldDescription,\n  FieldError,\n  FieldGroup,\n  FieldLabel,\n} from \"@/components/ui/field\"\nimport { Input } from \"@/components/ui/input\"\nimport { Label } from \"@/components/ui/label\"\nimport { Separator } from \"@/components/ui/separator\"\nimport { Toaster } from \"@/components/ui/sonner\"\nimport { IconPlaceholder } from \"@/components/icons/icon-placeholder\"\n\nconst BRAND = \"Acme\"\nconst PLANS = [\n  { label: \"Free\", detail: \"Up to 3 projects, 1 GB storage\", popular: false },\n  {\n    label: \"Pro\",\n    detail: \"Unlimited projects, 50 GB storage\",\n    popular: true,\n  },\n  {\n    label: \"Team\",\n    detail: \"Everything in Pro + admin controls\",\n    popular: false,\n  },\n]\n\nconst signUpSchema = z.object({\n  firstName: z.string().min(1, \"First name is required\"),\n  lastName: z.string().min(1, \"Last name is required\"),\n  email: z\n    .string()\n    .min(1, \"Email is required\")\n    .email(\"Enter a valid email address\"),\n  password: z\n    .string()\n    .min(8, \"Password must be at least 8 characters\")\n    .regex(/[0-9]/, \"Include at least one number\"),\n})\n\nexport default function AuthBlock() {\n  const [agreed, setAgreed] = useState(false)\n  const [errors, setErrors] = useState<Record<string, string>>({})\n\n  function handleSubmit(event: React.FormEvent<HTMLFormElement>) {\n    event.preventDefault()\n    const data = Object.fromEntries(new FormData(event.currentTarget))\n    const result = signUpSchema.safeParse(data)\n    if (!result.success) {\n      const next: Record<string, string> = {}\n      for (const issue of result.error.issues) {\n        const key = issue.path[0]\n        if (typeof key === \"string\" && !next[key]) {\n          next[key] = issue.message\n        }\n      }\n      setErrors(next)\n      return\n    }\n    setErrors({})\n    toast.promise(new Promise((resolve) => setTimeout(resolve, 1400)), {\n      loading: \"Creating your account…\",\n      success: \"Account created. Check your inbox to verify.\",\n      error: \"Could not create account. Please try again.\",\n    })\n  }\n\n  function clearError(name: string) {\n    setErrors((prev) => {\n      if (!prev[name]) return prev\n      const next = { ...prev }\n      delete next[name]\n      return next\n    })\n  }\n\n  return (\n    <section className=\"flex w-full items-center justify-center bg-background px-6 py-12 text-foreground\">\n      <Toaster />\n      <div className=\"flex w-full max-w-3xl flex-col gap-0 overflow-hidden rounded-xl md:flex-row\">\n        <div className=\"flex flex-col gap-6 border border-border bg-muted px-8 py-10 md:w-2/5\">\n          <div className=\"flex flex-col gap-1\">\n            <span className=\"text-base font-bold tracking-tight\">{BRAND}</span>\n            <p className=\"text-xs text-muted-foreground\">\n              One account. Every plan.\n            </p>\n          </div>\n\n          <Separator />\n\n          <ul className=\"flex flex-col gap-4\">\n            {PLANS.map((plan) => (\n              <li key={plan.label} className=\"flex items-start gap-3\">\n                <span className=\"mt-0.5 flex size-5 shrink-0 items-center justify-center rounded-md bg-foreground text-background\">\n                  <IconPlaceholder\n                    lucide=\"Check\"\n                    tabler=\"IconCheck\"\n                    hugeicons=\"Tick02Icon\"\n                    phosphor=\"Check\"\n                    remixicon=\"RiCheckLine\"\n                    className=\"size-3\"\n                    aria-hidden=\"true\"\n                  />\n                </span>\n                <div className=\"flex flex-col gap-0.5\">\n                  <span className=\"flex items-center gap-2 text-sm font-semibold\">\n                    {plan.label}\n                    {plan.popular && (\n                      <Badge\n                        variant=\"secondary\"\n                        className=\"h-4 px-1 text-[9px] font-medium tracking-wide uppercase\"\n                      >\n                        Popular\n                      </Badge>\n                    )}\n                  </span>\n                  <span className=\"text-xs text-muted-foreground\">\n                    {plan.detail}\n                  </span>\n                </div>\n              </li>\n            ))}\n          </ul>\n\n          <Separator />\n\n          <p className=\"text-xs text-muted-foreground\">\n            No credit card required to get started. Upgrade any time.\n          </p>\n        </div>\n\n        <div className=\"flex flex-1 flex-col gap-8 border border-border bg-card px-8 py-10 md:border-l-0\">\n          <CardHeader className=\"p-0\">\n            <div className=\"flex items-center gap-3\">\n              <span className=\"flex size-9 items-center justify-center rounded-lg border border-border bg-muted text-foreground\">\n                <IconPlaceholder\n                  lucide=\"UserPlus\"\n                  tabler=\"IconUserPlus\"\n                  hugeicons=\"UserAddIcon\"\n                  phosphor=\"UserPlus\"\n                  remixicon=\"RiUserAddLine\"\n                  className=\"size-4\"\n                  aria-hidden=\"true\"\n                />\n              </span>\n              <div className=\"flex flex-col gap-0.5\">\n                <CardTitle className=\"text-base font-bold\">\n                  Create your account\n                </CardTitle>\n                <CardDescription>\n                  Get started with {BRAND}, free forever.\n                </CardDescription>\n              </div>\n            </div>\n          </CardHeader>\n\n          <CardContent className=\"p-0\">\n            <form\n              className=\"flex flex-col gap-6\"\n              onSubmit={handleSubmit}\n              noValidate\n            >\n              <FieldGroup>\n                <div className=\"flex flex-col gap-5 sm:flex-row\">\n                  <Field className=\"flex-1\">\n                    <FieldLabel htmlFor=\"first-name\">First name</FieldLabel>\n                    <Input\n                      id=\"first-name\"\n                      name=\"firstName\"\n                      type=\"text\"\n                      placeholder=\"Jordan\"\n                      autoComplete=\"given-name\"\n                      aria-invalid={!!errors.firstName}\n                      onChange={() => clearError(\"firstName\")}\n                    />\n                    <FieldError>{errors.firstName}</FieldError>\n                  </Field>\n                  <Field className=\"flex-1\">\n                    <FieldLabel htmlFor=\"last-name\">Last name</FieldLabel>\n                    <Input\n                      id=\"last-name\"\n                      name=\"lastName\"\n                      type=\"text\"\n                      placeholder=\"Blake\"\n                      autoComplete=\"family-name\"\n                      aria-invalid={!!errors.lastName}\n                      onChange={() => clearError(\"lastName\")}\n                    />\n                    <FieldError>{errors.lastName}</FieldError>\n                  </Field>\n                </div>\n\n                <Field>\n                  <FieldLabel htmlFor=\"email\">Work email</FieldLabel>\n                  <Input\n                    id=\"email\"\n                    name=\"email\"\n                    type=\"email\"\n                    placeholder=\"jordan@company.com\"\n                    autoComplete=\"email\"\n                    aria-invalid={!!errors.email}\n                    onChange={() => clearError(\"email\")}\n                  />\n                  <FieldError>{errors.email}</FieldError>\n                </Field>\n\n                <Field>\n                  <FieldLabel htmlFor=\"password\">Password</FieldLabel>\n                  <Input\n                    id=\"password\"\n                    name=\"password\"\n                    type=\"password\"\n                    placeholder=\"••••••••\"\n                    autoComplete=\"new-password\"\n                    aria-invalid={!!errors.password}\n                    onChange={() => clearError(\"password\")}\n                  />\n                  {errors.password ? (\n                    <FieldError>{errors.password}</FieldError>\n                  ) : (\n                    <FieldDescription>\n                      Minimum 8 characters, at least one number.\n                    </FieldDescription>\n                  )}\n                </Field>\n              </FieldGroup>\n\n              <div className=\"flex items-start gap-2.5\">\n                <Checkbox\n                  id=\"terms\"\n                  name=\"terms\"\n                  className=\"mt-px\"\n                  checked={agreed}\n                  onCheckedChange={(checked) => setAgreed(checked === true)}\n                />\n                <Label\n                  htmlFor=\"terms\"\n                  className=\"text-xs leading-relaxed text-muted-foreground\"\n                >\n                  I agree to the{\" \"}\n                  <a\n                    href=\"#\"\n                    className=\"font-medium text-foreground underline-offset-4 hover:underline\"\n                  >\n                    Terms of Service\n                  </a>{\" \"}\n                  and{\" \"}\n                  <a\n                    href=\"#\"\n                    className=\"font-medium text-foreground underline-offset-4 hover:underline\"\n                  >\n                    Privacy Policy\n                  </a>\n                </Label>\n              </div>\n\n              <Button\n                type=\"submit\"\n                size=\"lg\"\n                className=\"w-full\"\n                disabled={!agreed}\n              >\n                Create Account\n                <IconPlaceholder\n                  lucide=\"ArrowRight\"\n                  tabler=\"IconArrowRight\"\n                  hugeicons=\"ArrowRightIcon\"\n                  phosphor=\"ArrowRight\"\n                  remixicon=\"RiArrowRightLine\"\n                  data-icon=\"inline-end\"\n                />\n              </Button>\n            </form>\n          </CardContent>\n\n          <CardFooter className=\"justify-center border-none p-0 text-xs text-muted-foreground\">\n            Already have an account?\n            <Button\n              variant=\"link\"\n              className=\"px-1 text-xs\"\n              render={<a href=\"#\" />}\n              nativeButton={false}\n            >\n              Sign In\n            </Button>\n          </CardFooter>\n        </div>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "meta": {
    "height": "657px",
    "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": [
    "auth"
  ],
  "type": "registry:block"
}