Components / Actions
UserMenu
Your account, settings, theme, and sign out behind the avatar. Opens as a bottom sheet on phones.
Install
npx shadcn@latest add https://irisui.dev/r/user-menu.jsonimport { UserMenu } from "@/components/iris/user-menu/user-menu";Preview
UserMenu
The account menu behind a person's avatar in an app's top bar: identity header, a few account destinations, inline status and theme switches, and sign out — opening as a bottom sheet on phones.
When to use
- The signed-in user's entry point in a top bar or sidebar footer.
- When presence (available / busy / away) or a light / dark / system preference should be changeable without leaving the menu.
- For general action menus, use
DropdownMenu. For a standalone light/dark toggle, useThemeSwitch.
Usage
import { UserMenu } from "@/components/iris/user-menu/user-menu";
<UserMenu
user={{ name: "Katerina Vlachou", email: "katerina@studio.example", plan: "Team" }}
showName
status={status}
onStatusChange={setStatus}
theme={theme}
onThemeChange={setTheme}
items={[
{ label: "Profile", icon: <UserIcon size={15} />, onSelect: openProfile },
{ label: "Settings", icon: <SettingsIcon size={15} />, keys: ["⌘", ","], onSelect: openSettings },
]}
onSignOut={() => auth.signOut()}
/>;
Props
| Prop | Type | Default | Description |
|---|---|---|---|
user |
{ name, email, plan?, avatarSrc?, avatarSrcSet? } |
— | Required. Without avatarSrc the trigger and header show initials. |
items |
{ label, icon?, keys?, onSelect? }[] |
[] |
Account destinations with optional shortcut hints. Keep it to three or four. |
onSignOut |
() => void | Promise<unknown> |
— | Sign out handler. A promise shows progress on the item and closes the menu when it settles. |
signOutKeys |
string[] |
— | Shortcut hint for sign out. |
status / defaultStatus / onStatusChange |
"available" | "busy" | "away" |
"available" |
Passing status or onStatusChange shows the presence dot and an inline status switch. |
theme / defaultTheme / onThemeChange |
"light" | "dark" | "system" |
"system" |
Theme preference; applying it to the page is up to the app. |
showTheme |
boolean |
true |
Shows the inline light / dark / system switch. |
showName |
boolean |
false |
Shows the name and a chevron beside the avatar from 640px up. |
align |
"start" | "center" | "end" |
"end" |
Panel alignment to the trigger. |
open / defaultOpen / onOpenChange |
boolean |
false |
Controlled or uncontrolled open state. |
portal |
boolean |
true |
Renders the desktop panel in a portal on <body>; false keeps it inside the trigger's wrapper. |
ref |
Ref<HTMLButtonElement> |
— | The trigger button. |
className |
string |
— | Extra class on the trigger button. |
Notes
- The trigger is labelled "Account menu, {name}, {status}" with
aria-haspopup="menu". The panel isrole="menu"; arrow keys move between items and into the status/theme segments (menuitemradio), Escape or Tab closes and returns focus to the trigger. - Theme and status choices keep the menu open; everything else closes it.
- Below 640px (
max-width: 639px) it opens as a bottom sheet instead of an anchored panel. - Presence dots differ by shape as well as colour (solid, barred, hollow);
PresenceDotis also exported for use elsewhere.