Axon 911 Frontend DocsAxon 911 Frontend Docs
Axon 911 Frontend Docs
    Loading navigation…
U
User
Switch to light mode
  1. Components
  2. User Menu
  3. Usage

User Menu

Usage

Import @prepared911/ui/user-menu and @prepared911/ui/user-menu/styles.css. UserMenu renders other components, whose stylesheets are separate, so also load @prepared911/ui/avatar/styles.css, @prepared911/ui/badge/styles.css, @prepared911/ui/box/styles.css, @prepared911/ui/button/styles.css, @prepared911/ui/icon/styles.css, @prepared911/ui/menu/styles.css, @prepared911/ui/segmented-control/styles.css, @prepared911/ui/status-dot/styles.css and @prepared911/ui/text/styles.css, and the stylesheets Menu's usage page lists. The Reduce motion row needs no Switch stylesheet: its track is an internal part that menu/styles.css already holds. UserMenu is the account menu behind a person's avatar in an app's top bar. The trigger is the avatar (photo or initials). A presence dot is optional and absent unless you pass a status. The panel leads with an identity header, then the account destinations, a preferences group, and Sign out.
This is the default story: no presence dot, no availability rows, no shortcut hints, and a neutral Sign out. triggerLabel is the accessible name of the trigger. Write it to include the person's name, for example "Dana Levi, account menu". To open the menu from another control, such as the preferences icon button of a top bar, pass it as trigger instead and drop triggerLabel. The control keeps its own name; the menu adds the button attributes and returns focus to it on close. See the Navbar contract (NB-16).
Trigger
  • Without showName the trigger is the avatar alone. With showName it also draws the name (one line, capped at 12rem) and a chevron that turns while the menu is open, from 640px of viewport width up. The accessible name is the same either way and the button element is the same, so a window that resizes across 640px keeps focus.
  • The photo comes from avatarSrc. Without it, or when it fails to load, the avatar shows initials, which default to the first letter of each of the first two words of name.
  • Passing status (or defaultStatus, or onStatusChange) adds a presence dot to the avatar; without one nothing renders. See Availability.
  • A press toggles the menu. ArrowDown on the trigger opens it on the first row and ArrowUp on the last. Focus moves into the menu only when a person opens it: a menu that opens through defaultOpen or a controlled open does not take focus.
Panel
  • The header shows a larger avatar, the name, an optional plan badge (plan), and the email. The name and email truncate to one line and keep their full text as a title.
  • items are the account destinations: label, optional icon, optional shortcut hint, onSelect(). Pressing one runs onSelect, closes the menu, and returns focus to the trigger. A shortcut is optional and a visual hint only (it is hidden from assistive technology); the app binds the key. See Shortcuts.
  • The panel aligns to the end of the trigger by default (align="end") and opens below it (side="block-end").
  • Row highlights are concentric with the panel's rounded corners, in both writing directions: the panel is Menu's surface, and its rows take Menu's row radius (MN-33 in packages/ui/src/components/menu/CONTRACT.md).
  • Every option takes Menu's one gliding highlight, the Theme row included: the pointer glides it between rows, arrow keys jump it, it jumps under reduced motion, and it hides under forced colors in favor of the focused row's edge. The header takes none.
Preferences
Preference rows keep the menu open. A row is drawn when the app passes its copy, and UserMenu only reports the choice: the app applies it.
RowPropsReports
ThemeappearanceLabels, appearance, defaultAppearance, onAppearanceChangeAppearanceMode.Light, Dark or System
Reduce motionreduceMotionLabel, reduceMotion, defaultReduceMotion, onReduceMotionChangetrue or false
AvailabilitystatusLabels, status, defaultStatus, onStatusChangeUserMenuStatus.Available, Busy or Away
preferencesLabel puts the rows under a visible heading. Every on/off preference row (Reduce motion today) is one menuitemcheckbox with aria-checked that draws the design system's Switch track at the inline end. The whole row toggles on a press, Enter or Space, and the menu stays open. The track is a picture: it has no input and no tab stop, so no control nests inside the row. An uncontrolled preference survives closing and reopening the menu.
Applying the preferences
The app owns the effect. A minimal wiring:
The reduce motion contract (data-motion="reduced" on <html>, MotionPreference and applyMotionPreference()) is owned by the motion preference work; UserMenu does not import it. Pass details.cancel() in a change handler to refuse a change.
Availability
Availability is optional. The default menu has no status dot and no Available, Busy or Away rows. Passing status, defaultStatus or onStatusChange shows the Available, Busy and Away rows (and then statusLabels is required) and a presence dot on the avatar in the color of the current status. The dot is decorative: the rows carry visible labels and the trigger's accessible name should carry the status, so triggerLabel may be a function of the status.
Sign out
Sign out is not a destructive action (owner ruling): it uses the neutral default item styling and takes no destructive intent, so it looks like any other row. onSignOut may return a promise. While it is pending the row shows a spinner, reads signingOutLabel, is aria-busy, and ignores further presses; the menu closes when the promise settles, resolved or rejected, and focus returns to the trigger. A rejection is not caught: handle the error in onSignOut. A callback that returns nothing closes the menu at once, like any destination.
Shortcuts
A destination takes an optional shortcut. None of the default examples set one, including Settings, but any item may:
The hint is drawn at the inline end of the row and hidden from assistive technology. UserMenu does not bind the key.
Open state
open, defaultOpen and onOpenChange(open, details) follow the design system's controlled and uncontrolled rules. details.reason is "trigger-press", "item-press", "focus-out" or "light-dismiss".
Small screens
Below 640px only the avatar shows and the panel stays a popover. A bottom sheet is a follow-up.
Previous
Tree / Accessibility
Next
User Menu / API and Development
On this page
Trigger
Panel
Preferences
Applying the preferences
Availability
Sign out
Shortcuts
Open state
Small screens