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.json
import { UserMenu } from "@/components/iris/user-menu/user-menu";
Registry item user-menuBrings in foundationRegistry JSON

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, use ThemeSwitch.

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 is role="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); PresenceDot is also exported for use elsewhere.