{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "user-button",
  "title": "User Button",
  "description": "Renders a user button with dropdown menu showing user info, settings link, plugin-contributed menu items (e.g. theme toggle, account switcher), and sign-in/sign-out actions.",
  "dependencies": [
    "@better-auth-ui/react@latest",
    "@better-auth-ui/core@latest",
    "better-auth",
    "lucide-react"
  ],
  "registryDependencies": [
    "button",
    "dropdown-menu",
    "spinner",
    "https://better-auth-ui.com/r/radix-nova/user-view.json"
  ],
  "files": [
    {
      "path": "src/components/auth/user/user-button.tsx",
      "content": "\"use client\"\n\nimport {\n  type MultiSessionAuthClient,\n  useAuth,\n  useSession,\n  useSetActiveSession\n} from \"@better-auth-ui/react\"\nimport {\n  ChevronsUpDown,\n  LogIn,\n  LogOut,\n  Settings,\n  UserPlus2\n} from \"lucide-react\"\nimport { isValidElement, type ReactElement, type ReactNode } from \"react\"\n\nimport { buttonVariants } from \"@/components/ui/button\"\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuGroup,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger\n} from \"@/components/ui/dropdown-menu\"\nimport { cn } from \"@/lib/utils\"\nimport { UserAvatar } from \"./user-avatar\"\nimport { UserView } from \"./user-view\"\n\n/** Auth states a `UserButton` link can be visible in. */\nexport type UserButtonLinkVisibility =\n  | \"authenticated\"\n  | \"unauthenticated\"\n  | \"always\"\n\n/** A simple link entry rendered as a `DropdownMenuItem` in the `UserButton` menu. */\nexport type UserButtonLink = {\n  /** Visible label. */\n  label: ReactNode\n  /** Destination URL. */\n  href: string\n  /** Optional leading icon. Sized/coloured to match built-in items. */\n  icon?: ReactNode\n  /** Forwarded to the underlying `DropdownMenuItem`. */\n  variant?: \"default\" | \"destructive\"\n  /**\n   * When this link is visible based on auth state.\n   * @default \"always\"\n   */\n  visibility?: UserButtonLinkVisibility\n}\n\nexport type UserButtonProps = {\n  className?: string\n  align?: \"center\" | \"end\" | \"start\" | undefined\n  sideOffset?: number\n  size?: \"default\" | \"icon\"\n  variant?:\n    | \"default\"\n    | \"destructive\"\n    | \"ghost\"\n    | \"link\"\n    | \"outline\"\n    | \"secondary\"\n  /** Additional menu entries rendered above the built-in items. */\n  links?: (UserButtonLink | ReactElement)[]\n  /** Hide the built-in \"Settings\" link. Useful when replacing it via `links`. */\n  hideSettings?: boolean\n}\n\nfunction renderUserLink(\n  link: UserButtonLink | ReactElement,\n  navigate: (options: { to: string; replace?: boolean }) => void,\n  fallbackKey: string\n): ReactNode {\n  if (isValidElement(link)) return link\n\n  const { label, href, icon, variant } = link\n  return (\n    <DropdownMenuItem\n      key={fallbackKey}\n      variant={variant}\n      onClick={() => navigate({ to: href })}\n    >\n      {icon}\n      {label}\n    </DropdownMenuItem>\n  )\n}\n\n/**\n * Render a user dropdown button that shows user info, settings, theme controls, and authentication actions.\n *\n * Includes user profile, settings link, optional multi-session account switching, theme picker,\n * and sign-in/sign-up/sign-out actions depending on authentication state.\n *\n * @param className - Additional CSS classes applied to the button trigger\n * @param align - Alignment of the dropdown menu relative to the trigger\n * @param sideOffset - Offset between the trigger and the dropdown menu\n * @param size - \"icon\" renders only the avatar; \"default\" renders a full button with label and chevron\n * @param variant - Visual variant of the trigger button\n * @param links - Additional menu entries rendered above the built-in items\n * @param hideSettings - Hide the built-in \"Settings\" link\n * @returns The dropdown menu component with user actions\n */\nexport function UserButton({\n  className,\n  align,\n  sideOffset,\n  size = \"default\",\n  variant = \"ghost\",\n  links,\n  hideSettings = false\n}: UserButtonProps) {\n  const { authClient, basePaths, viewPaths, localization, plugins, navigate } =\n    useAuth()\n\n  const { isPending: settingActiveSession } = useSetActiveSession(\n    authClient as MultiSessionAuthClient\n  )\n  const { data: session, isPending: sessionPending } = useSession(authClient)\n\n  const userLinks = links?.flatMap((link, index) => {\n    if (!isValidElement(link)) {\n      const visibility = link.visibility ?? \"always\"\n      if (visibility === \"authenticated\" && !session) return []\n      if (visibility === \"unauthenticated\" && session) return []\n    }\n    return [\n      renderUserLink(link, navigate, `user-button-link-${index.toString()}`)\n    ]\n  })\n\n  // Whether anything renders between the user info label and the\n  // sign-out item, so the leading separator isn't shown with nothing\n  // to separate (see #439).\n  const hasSessionMenuItems =\n    (userLinks?.length ?? 0) > 0 ||\n    !hideSettings ||\n    plugins.some((plugin) => (plugin.userMenuItems?.length ?? 0) > 0)\n\n  return (\n    <DropdownMenu>\n      <DropdownMenuTrigger\n        aria-label={size === \"icon\" ? localization.auth.account : undefined}\n        className={\n          size === \"icon\"\n            ? cn(\"rounded-full\", className)\n            : cn(\n                buttonVariants({ variant, size: \"lg\" }),\n                \"py-2.5 h-auto font-normal\",\n                className\n              )\n        }\n      >\n        {size === \"icon\" ? (\n          <UserAvatar />\n        ) : (\n          <>\n            {session || sessionPending || settingActiveSession ? (\n              <UserView isPending={!!settingActiveSession} />\n            ) : (\n              <>\n                <UserAvatar />\n\n                <div className=\"grid flex-1 text-left text-sm leading-tight\">\n                  {localization.auth.account}\n                </div>\n              </>\n            )}\n\n            <ChevronsUpDown className=\"ml-auto size-4\" />\n          </>\n        )}\n      </DropdownMenuTrigger>\n\n      <DropdownMenuContent\n        className=\"min-w-40 md:min-w-56 max-w-[48svw]\"\n        sideOffset={sideOffset}\n        align={align}\n      >\n        {session && (\n          <>\n            <DropdownMenuGroup>\n              <DropdownMenuLabel className=\"text-sm font-normal\">\n                <UserView />\n              </DropdownMenuLabel>\n            </DropdownMenuGroup>\n\n            {hasSessionMenuItems && <DropdownMenuSeparator />}\n          </>\n        )}\n\n        {session ? (\n          <>\n            {userLinks}\n\n            {!hideSettings && (\n              <DropdownMenuItem\n                onClick={() =>\n                  navigate({\n                    to: `${basePaths.settings}/${viewPaths.settings.account}`\n                  })\n                }\n              >\n                <Settings className=\"text-muted-foreground\" />\n\n                {localization.settings.settings}\n              </DropdownMenuItem>\n            )}\n\n            {plugins.flatMap((plugin) =>\n              plugin.userMenuItems?.map((Item, index) => (\n                <Item key={`${plugin.id}-${index.toString()}`} />\n              ))\n            )}\n\n            <DropdownMenuSeparator />\n\n            <DropdownMenuItem\n              onClick={() =>\n                navigate({\n                  to: `${basePaths.auth}/${viewPaths.auth.signOut}`\n                })\n              }\n            >\n              <LogOut className=\"text-muted-foreground\" />\n\n              {localization.auth.signOut}\n            </DropdownMenuItem>\n          </>\n        ) : (\n          <>\n            {userLinks}\n\n            <DropdownMenuItem\n              onClick={() =>\n                navigate({\n                  to: `${basePaths.auth}/${viewPaths.auth.signIn}`\n                })\n              }\n            >\n              <LogIn className=\"text-muted-foreground\" />\n\n              {localization.auth.signIn}\n            </DropdownMenuItem>\n\n            <DropdownMenuItem\n              onClick={() =>\n                navigate({\n                  to: `${basePaths.auth}/${viewPaths.auth.signUp}`\n                })\n              }\n            >\n              <UserPlus2 className=\"text-muted-foreground\" />\n\n              {localization.auth.signUp}\n            </DropdownMenuItem>\n\n            {plugins.flatMap((plugin) =>\n              plugin.userMenuItems?.map((Item, index) => (\n                <Item key={`${plugin.id}-${index.toString()}`} />\n              ))\n            )}\n          </>\n        )}\n      </DropdownMenuContent>\n    </DropdownMenu>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/auth/user/user-button.tsx"
    }
  ],
  "type": "registry:component"
}