npx shadcn@latest add https://sdk-components.thesqd.com/r/user-menu.jsonimport { UserMenu, type UserMenuItem } from "@/components/blocks/user-menu";import { SealCheck as BadgeCheckIcon, SignOut as LogOutIcon } from "@phosphor-icons/react/ssr";
import { UserMenu } from "@/components/blocks/user-menu";
export function Example() {
return (
<UserMenu
user={{ name: "Kurt Cobain", email: "kurt@nirvana.com", initials: "KC" }}
items={[
{ type: "item", label: "Account", icon: BadgeCheckIcon },
{ type: "separator" },
{ type: "item", label: "Log out", icon: LogOutIcon, destructive: true },
]}
/>
);
}UserMenu (props)
├── user: { name, email?, avatarSrc?, initials? }
├── size?: "default" | "sm" // "sm" = input-height trigger, no email line (default: "default")
├── readOnly?: boolean // static card — no dropdown, no chevron (default: false)
├── showHeader?: boolean // include avatar+name card at top of menu (default: true)
├── showOnlineStatus?: boolean // show a presence dot on the avatar (default: false)
├── status: "online" | "idle" | "offline" // required when showOnlineStatus — green / amber / grey
├── side?: "top" | "bottom" | "left" | "right" // dropdown anchor side (default: "top")
├── align?: "start" | "center" | "end" // dropdown alignment (default: "start")
├── items: UserMenuItem[] // omit only under readOnly
│ ├── { type: "item", label, icon?, onClick?, disabled?, destructive? }
│ ├── { type: "separator" }
│ └── { type: "label", content }
└── className?: string
Self-contained — no sidebar context required. Drop anywhere: a SidebarFooter,
a navbar, a settings page header.UserMenu
| Prop | Type | Default | Description |
|---|---|---|---|
user | { name; email?; avatarSrc?; initials? } | — | User identity for the trigger badge and the optional menu header. |
items | UserMenuItem[] | — | Array of menu rows (discriminated union of item / separator / label). Optional only under `readOnly`. |
showHeader | boolean | true | Include a non-interactive user card at the top of the menu. |
size | "default" | "sm" | "default" | `sm` shrinks the trigger to input height (h-9) with a small avatar and hides the email line. The dropdown header keeps the full identity card. |
readOnly | boolean | false | Render a static identity card — no dropdown, no chevron, not focusable. `items` is ignored. |
showOnlineStatus | boolean | false | Show a presence dot on the avatar (trigger and menu header). |
status | "online" | "idle" | "offline" | — | Required when `showOnlineStatus` is true. Green for online, amber for idle, grey for offline. |
side | "top" | "bottom" | "left" | "right" | "top" | Anchor side for the dropdown. |
align | "start" | "center" | "end" | "start" | Anchor alignment along the side. |
className | string | — | Extend the resolved trigger classes. |
UserMenuItem
| Prop | Type | Default | Description |
|---|---|---|---|
type | "item" | "separator" | "label" | — | Discriminator. `item` is an actionable row. |
label | ReactNode | — | Row label (item only). |
icon | Icon | — | Optional leading icon (item only). |
onClick | () => void | — | Fires when the item is activated. |
destructive | boolean | — | Renders the item in red tonal (log out, delete). |
disabled | boolean | — | Disables the item. |