User menu

Prop-driven user-profile menu — avatar, name, email, dropdown actions.

Installation
$Terminal
npx shadcn@latest add https://sdk-components.thesqd.com/r/user-menu.json
Usage
Pass a `user` and an `items` array. Self-contained — no sidebar context required.
TSImport
import { UserMenu, type UserMenuItem } from "@/components/blocks/user-menu";
TSExample
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 },
      ]}
    />
  );
}
Composition
Anatomy of the UserMenu block.
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.
Default
Avatar + name + email trigger with a chevron. Dropdown opens above the trigger by default — good for sidebar footers. Override with `side` / `align`.
Minimal
Hide the in-menu header with `showHeader={false}` when the trigger already carries the identity. Good for small menus with only a couple of actions.
Online status
Set `showOnlineStatus` to put a presence dot on the avatar. `status` is then required — green for online, amber for idle, grey for offline.
Small
Set `size="sm"` for a trigger the same height as an Input — small avatar, name only, no email. Use it in navbars and toolbars where the two-line default is too tall.
Read only
Set `readOnly` to drop the dropdown, the chevron and the focus ring — the same identity card, static. Use it for profile headers and account panels where there is nothing to open.
Kurt Cobain
Kurt Cobainkurt@nirvana.com
Grouped sections
Use `{ type: "label" }` rows to group items under section headings (Account, Billing, etc.).
API Reference
Props for UserMenu and its item shape.

UserMenu

PropTypeDefaultDescription
user{ name; email?; avatarSrc?; initials? }—User identity for the trigger badge and the optional menu header.
itemsUserMenuItem[]—Array of menu rows (discriminated union of item / separator / label). Optional only under `readOnly`.
showHeaderbooleantrueInclude 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.
readOnlybooleanfalseRender a static identity card — no dropdown, no chevron, not focusable. `items` is ignored.
showOnlineStatusbooleanfalseShow 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.
classNamestring—Extend the resolved trigger classes.

UserMenuItem

PropTypeDefaultDescription
type"item" | "separator" | "label"—Discriminator. `item` is an actionable row.
labelReactNode—Row label (item only).
iconIcon—Optional leading icon (item only).
onClick() => void—Fires when the item is activated.
destructiveboolean—Renders the item in red tonal (log out, delete).
disabledboolean—Disables the item.