Skip to content

Profile Menu

<loomi-profile-menu> - a compact profile trigger with avatar, name, description, chevron, and a dropdown menu. It composes <loomi-card>, <loomi-avatar>, and <loomi-dropmenu>, so avatar dots, pulsing dots, verification badges, and menu-item behavior all come from the existing Loomi primitives.

Terminal window
npm install @loomidev/profile-menu lit
import "@loomidev/profile-menu";

Put <loomi-dropmenu-item> elements inside the profile menu. Clicking the card trigger opens the dropdown. The items are slotted through to the internal menu, not moved into it, so they stay in your document and your page CSS (including ::part() selectors) keeps styling them and their content.

Profile Settings Sign out
<loomi-profile-menu
name="Alice Wonderland"
description="alice@loomiui.com"
avatar="/avatars/female.jpg"
>
<loomi-dropmenu-item icon="user-circle">Profile</loomi-dropmenu-item>
<loomi-dropmenu-item icon="cog-6-tooth">Settings</loomi-dropmenu-item>
<loomi-dropmenu-item divider></loomi-dropmenu-item>
<loomi-dropmenu-item icon="arrow-right-start-on-rectangle" variant="destructive">
Sign out
</loomi-dropmenu-item>
</loomi-profile-menu>

Avatar behavior is passed to the internal <loomi-avatar>.

Account
<loomi-profile-menu
name="Alice Wonderland"
description="alice@loomiui.com"
avatar="/avatars/female.jpg"
dotted
pulse-dot
verified
dot-color="success"
dot-position="top"
>
<loomi-dropmenu-item>Account</loomi-dropmenu-item>
</loomi-profile-menu>

If avatar is blank, initials are derived from name. Set avatar-label to control the fallback text yourself.

By default the avatar leads the trigger. Set avatar-position="right" to flip it: the name and description lead, the avatar follows, and the chevron stays at the trailing edge - so the menu still opens aligned under the chevron. The avatar keeps a 6px gap from the identity labels in either position.

Profile Settings
<loomi-profile-menu
avatar-position="right"
name="Alice Wonderland"
description="alice@loomiui.com"
avatar="/avatars/female.jpg"
>
<loomi-dropmenu-item icon="user-circle">Profile</loomi-dropmenu-item>
<loomi-dropmenu-item icon="cog-6-tooth">Settings</loomi-dropmenu-item>
</loomi-profile-menu>

This variant suits right-aligned app headers, where the avatar reads better closest to the edge of the screen. Everything else - avatar dots, verification badge, transparent trigger, and menu behavior - works exactly the same.

Use transparent when the profile menu sits on an existing surface and should not add its own card fill. Add has-hover when you want a very subtle border on hover.

Profile
<loomi-profile-menu
transparent
has-hover
name="Alice Wonderland"
description="alice@loomiui.com"
avatar-label="AW"
>
<loomi-dropmenu-item>Profile</loomi-dropmenu-item>
</loomi-profile-menu>

The menu is powered by <loomi-dropmenu>, so the same placement, divided rows, scrolling, keyboard navigation, and hide-after-click behavior apply.

The menu is positioned from the chevron rather than the whole card, so its arrow lands on the chevron whichever side the avatar is on and whichever way the panel aligns, flips, or swaps near a viewport edge. placement="right" ends the panel just past the chevron; placement="left" starts it just before the chevron and lets it extend beyond the card. When compact, it’s positioned from the avatar + chevron pair instead. (This is <loomi-dropmenu>’s arrowAnchor property, set for you.)

Profile Settings
<loomi-profile-menu name="Alice Wonderland" placement="right" divided>
<loomi-dropmenu-item icon="user-circle">Profile</loomi-dropmenu-item>
<loomi-dropmenu-item icon="cog-6-tooth">Settings</loomi-dropmenu-item>
</loomi-profile-menu>

A menu row can hold a full-width button instead of a text action. hover="false" keeps the row from tinting behind the button.

Profile Settings Sign out
<loomi-profile-menu name="Alice Wonderland" description="alice@loomiui.com">
<loomi-dropmenu-item icon="user-circle">Profile</loomi-dropmenu-item>
<loomi-dropmenu-item icon="cog-6-tooth">Settings</loomi-dropmenu-item>
<loomi-dropmenu-item divider></loomi-dropmenu-item>
<loomi-dropmenu-item hover="false">
<loomi-button full-width outline color="error" size="small">Sign out</loomi-button>
</loomi-dropmenu-item>
</loomi-profile-menu>

In a tight header, compact reduces the trigger to avatar + chevron. Use compact="auto" to do that only on viewports narrower than 40rem (640px) and keep the full card above it. The name and description are visually hidden, not removed, so the trigger button keeps them as its accessible name.

Acme Profile
<header style="display:flex;align-items:center;gap:0.5rem">
<img src="/logo.svg" alt="Acme" width="126" />
<loomi-tag label="Beta"></loomi-tag>
<loomi-profile-menu name="Alice Wonderland" description="alice@loomiui.com" compact="auto" style="margin-inline-start:auto">
<loomi-dropmenu-item icon="user-circle">Profile</loomi-dropmenu-item>
</loomi-profile-menu>
</header>

loomi-profile-menu uses a real dropmenu trigger button from <loomi-dropmenu>, and menu rows keep the menu roles and keyboard behavior from <loomi-dropmenu-item>.

  • Use a clear name and description; they become the visible trigger text.
  • Use avatar-alt when the avatar image needs a specific accessible description.
  • Keep destructive actions marked with variant="destructive" on the menu item.

For the library-wide baseline, see Foundations - Accessibility.

The trigger is shrink-wrapped by default, with ellipsis truncation for long names and descriptions, and a minimum width of min(14rem, 100vw). Use compact / compact="auto" on phones (see above), or set --loomi-profile-menu-min-width: 0 to let the full trigger shrink with a constrained container, truncating the name instead of overflowing.

Style the trigger’s pieces with ::part():

loomi-profile-menu::part(trigger) { padding: 0.5rem; }
loomi-profile-menu::part(name) { font-weight: 600; }

For the shared container and viewport rules, see Foundations - Responsive behavior.

loomi-profile-menu uses Loomi semantic tokens such as --loomi-surface, --loomi-surface-border, --loomi-text, and --loomi-text-muted, so the trigger and menu inherit your app theme.

For theme activation, token overrides, and contrast guidance, see Foundations - Dark mode.

AttributeDefaultDescription
name(blank)Main identity text. Also used for avatar initials when avatar-label is blank.
description(blank)Secondary text under the name, often an email or role.
avatar(blank)Avatar image URL.
avatar-labelderivedInitials/fallback label for the internal <loomi-avatar>.
avatar-altderivedAccessible alt text for the avatar image.
avatar-sizeregularPassed to the internal <loomi-avatar>. tiny | small | regular | medium | big | huge | omg. See Sizing.
avatar-bg-colorgrayInitials background color passed to <loomi-avatar>.
avatar-positionleftWhere the avatar sits in the trigger. left | right. With right, the copy leads and the chevron stays trailing.
dottedfalseShow avatar status dot. (boolean)
pulse-dotfalseAnimate the avatar status dot. (boolean)
dot-colorsuccessStatus dot color.
dot-positionbottomtop | bottom.
verifiedfalseShow the avatar verification badge. (boolean)
has-hoverfalseShow a subtle border on trigger hover/focus. (boolean)
transparentfalseRemove the trigger card fill. (boolean)
compactoffcompact (or compact="always") shows only avatar + chevron; compact="auto" does so below a 40rem viewport.
placementrightDropmenu placement. auto | left | right. Defaults to right so the menu opens right-aligned, under the chevron.
dividedfalseAdd dividers between menu items. (boolean)
scrollablefalseCap menu height and scroll overflow. (boolean)
height200Scrollable menu height in pixels.
hide-after-clicktrueClose the menu after clicking a non-toggle item. (boolean)

Parts: trigger, avatar, copy, name, description, chevron. CSS custom properties: --loomi-profile-menu-min-width (default min(14rem, 100vw)), --loomi-profile-menu-radius.

SlotDescription
(default)<loomi-dropmenu-item> menu rows.
  • @loomidev/avatar
  • @loomidev/card
  • @loomidev/core
  • @loomidev/dropmenu
  • @loomidev/icons
  • @loomidev/theme