Components
UserMenu
The signed-in user's corner of the app: an avatar that opens a dropdown with their identity and account actions. Standalone, customizable, replaceable — and theme-aware inside a Header.
In the header
Drop it into the Header’s actions slot. The trigger shows the avatar; the panel opens with an identity header (name + detail line) above your items. It closes on outside click, Escape, or any item click — and inside a primary/dark Header the trigger’s hover ring adapts automatically.
import { AppShell, Header, UserMenu, UserMenuItem } from "appshell-react";
import { LogOut, Settings, User } from "lucide-react";
<Header
behavior="sticky"
logo={<span className="font-bold">Console</span>}
actions={
<UserMenu
username="Mara Kealoha"
detail="mara@terra.dev"
initials="MK" // or src="/avatar.jpg"
>
<UserMenuItem icon={<User />} label="Profile" href="/profile" />
<UserMenuItem icon={<Settings />} label="Settings" href="/settings" />
<UserMenuItem icon={<LogOut />} label="Log out" destructive onClick={signOut} />
</UserMenu>
}
/>Customize or replace
Every layer is swappable: trigger replaces the avatar button, children accepts anything (custom rows close the menu when they carry role="menuitem"), and open/onOpenChange hand you full control of the state. Don’t want the component at all? Avatar is exported standalone for building your own.
// Replace the trigger entirely — the dropdown behavior stays.
<UserMenu
username="Mara Kealoha"
detail="Administrator"
trigger={
<span className="flex items-center gap-2 rounded-full border py-1 pl-1 pr-3 text-sm">
<Avatar initials="MK" size="1.5rem" />
Mara
</span>
}
>
{/* any children work; clicks on role="menuitem" elements auto-close */}
<ThemeSwitcherRow />
<UserMenuItem label="Log out" destructive onClick={signOut} />
</UserMenu>
// In a Sidebar's bottom slot (the iX "infrastructure section" pattern):
<Sidebar variant="docked" bottomContent={
<div className="p-2"><UserMenu username="Mara" initials="MK" align="start">…</UserMenu></div>
}>…</Sidebar>animate-in entrance utilities as HeaderNav — install tw-animate-css for the fade/zoom entrance (it degrades gracefully without it).API
| Prop | Type | Default | Description |
|---|---|---|---|
| username* | string | — | Display name shown in the menu's info header. |
| detail | string | — | Secondary line under the name — an email, role, or tenant. |
| src | string | — | Avatar image URL for the trigger and info header. |
| initials | string | — | Avatar initials fallback. |
| trigger | ReactNode | — | Replace the default avatar button entirely. |
| open | boolean | — | Controlled open state. Omit for uncontrolled. |
| onOpenChange | (open: boolean) => void | — | Open-state change requests. |
| align | "start" | "end" | "end" | Horizontal alignment of the panel relative to the trigger. |
| children | ReactNode | — | Menu content — UserMenuItem elements or anything else. Clicks on role="menuitem" elements close the menu. |
| className | string | — | Extra classes for the dropdown panel. |
| triggerClassName | string | — | Extra classes for the default trigger button. |
| aria-label | string | — | Accessible name override for the trigger. Defaults to the "User menu" label. |
| Prop | Type | Default | Description |
|---|---|---|---|
| label* | string | — | Row text. |
| icon | ReactNode | — | Leading 16px icon. |
| href | string | — | Renders the row as a link (through the LinkProvider component) instead of a button. |
| onClick | () => void | — | Action handler. |
| destructive | boolean | false | Style as a destructive action — log out, delete account. |
| className | string | — | Extra classes. |
| Prop | Type | Default | Description |
|---|---|---|---|
| src | string | — | Image URL. Falls back to initials while missing or on load error. |
| alt | string | — | Image alt text. |
| initials | string | — | Shown when no image renders — keep it to 1–2 characters. |
| size | string | "2rem" | Diameter as a CSS length. |
| className | string | — | Extra classes. |