Nasaq

UserMenu

Avatar menu at the bottom of the sidebar - identity, your account items, theme and language submenus, and sign out.

PreviewOpen ↗

Code

import { DropdownMenuItem, SidebarFooter, UserMenu } from "@fadymondy/nasaq/web";import { CreditCard, UserRound } from "lucide-react";export function Footer() {  return (    <SidebarFooter>      <UserMenu user={{ name: "Fady Mondy", email: "[email protected]" }} onSignOut={() => console.log("sign out")}>        <DropdownMenuItem>          <UserRound />          Account        </DropdownMenuItem>        <DropdownMenuItem>          <CreditCard />          Billing        </DropdownMenuItem>      </UserMenu>    </SidebarFooter>  );}

Navigation · stable

Live examples and controls: UserMenu in the lab.

Install

npx shadcn@latest add https://docs.nasaqui.com/r/user-menu.json

The current user's menu, placed in SidebarFooter. The trigger shows avatar, name and email (avatar only on the collapsed rail). The menu shows the identity, then your items (Account, Billing…), then Theme and Language submenus, then Sign out. Nasaq supplies the frame and preferences; the product supplies the items.

When to use

  • The bottom of an AppShell sidebar, or (variant="avatar") the end of the header in a top-navigation app.
  • You want theme and language switching next to account actions without a separate settings screen.

When not to use

Import

import { UserMenu, type UserMenuUser } from "@fadymondy/nasaq/web";
// inside this monorepo: "@nasaq/web"

Quick start

import { DropdownMenuItem, SidebarFooter, UserMenu } from "@fadymondy/nasaq/web";
import { CreditCard, UserRound } from "lucide-react";

export function Footer() {
  return (
    <SidebarFooter>
      <UserMenu user={{ name: "Fady Mondy", email: "[email protected]" }} onSignOut={() => console.log("sign out")}>
        <DropdownMenuItem>
          <UserRound />
          Account
        </DropdownMenuItem>
        <DropdownMenuItem>
          <CreditCard />
          Billing
        </DropdownMenuItem>
      </UserMenu>
    </SidebarFooter>
  );
}

Anatomy

UserMenu
├─ trigger                     data-slot="user-menu"  (data-popup-open)
│  ├─ Avatar                   name, optional image
│  ├─ name + email             hidden on the rail; email wrapped in <bdi dir="ltr">
│  └─ chevrons-up-down         hidden on the rail
└─ menu
   ├─ identity header          avatar, name, email
   ├─ children group           your DropdownMenuItems
   ├─ Theme submenu            ThemeMenuItems (Light / Dark / System)      when preferences
   ├─ Language submenu         LocaleMenuItems, only with 2+ locales       when preferences
   └─ Sign out                 only with onSignOut

API

UserMenuUser

FieldTypeDescription
namestringDisplay name. Also drives the avatar initials.
emailstringShown under the name, isolated as LTR.
avatar?stringImage URL.

UserMenu

PropTypeDefaultDescription
userUserMenuUserrequiredThe signed-in user.
children?ReactNodenoneProduct items (DropdownMenuItems) above the preferences.
preferences?booleantrueAdds the Theme and Language submenus. Language shows only when the provider has more than one locale.
profile?PersonProfilenoneTurns the menu header into a profile card (role, presence, local time, team) and the trigger avatar into one with a presence dot.
onViewProfile?(person) => voidnoneAdds View profile to that card.
onSignOut?() => voidnoneAdds a "Sign out" item. Without it there is no sign-out item and no trailing separator.
variant?"sidebar" | "avatar""sidebar""sidebar": a full-width row with name and email at the foot of the sidebar. "avatar": only the round avatar, for the header of a top-navigation app; the menu opens below it.
className?stringnoneClasses for the trigger.
labels?{ theme?: string; language?: string; signOut?: string }EN/AR built inTheme ("Theme"/"المظهر"), Language ("Language"/"اللغة"), Sign out ("Sign out"/"تسجيل الخروج").

It needs NasaqProvider (theme, locale, locales) and reads the rail state from AppShell.

Examples

Product items including "Customize sidebar"

import { DropdownMenuItem, UserMenu } from "@fadymondy/nasaq/web";
import { Bell, Settings, SlidersHorizontal } from "lucide-react";

export const Menu = ({ onCustomize }: { onCustomize: () => void }) => (
  <UserMenu user={{ name: "Fady Mondy", email: "[email protected]", avatar: "/me.png" }} onSignOut={() => {}}>
    <DropdownMenuItem><Bell />Notifications</DropdownMenuItem>
    <DropdownMenuItem onClick={onCustomize}><SlidersHorizontal />Customize sidebar</DropdownMenuItem>
    <DropdownMenuItem><Settings />Settings</DropdownMenuItem>
  </UserMenu>
);

Arabic labels, no preferences

import { UserMenu } from "@fadymondy/nasaq/web";

export const Ar = () => (
  <UserMenu
    user={{ name: "فادي مندي", email: "[email protected]" }}
    preferences={false}
    onSignOut={() => {}}
    labels={{ signOut: "تسجيل الخروج" }}
  />
);

Accessibility

KeyAction
Enter / Space / ↓ on triggerOpens the menu.
↑ ↓ / Home EndMove through items.
→ (LTR) / ← (RTL) on a submenu rowOpens Theme or Language. ←/→ reverse to close.
Enter / SpaceActivates the item (radio items for theme and language are single choice).
EscCloses the menu (or submenu) and returns focus.
  • Trigger: menu button; on the rail aria-label is the user's name.
  • Theme and language options are radio items, so the current choice is exposed to assistive tech.
  • Localise: labels and your own item text.

RTL & i18n

  • The email is wrapped in <bdi dir="ltr"> so it stays readable in Arabic, while the line stays aligned to the reading start.
  • On the rail the menu opens to the inline end and aligns to the end; expanded it opens upward (top).
  • The language list shows each language in its own script with lang/dir set.
  • Built-in labels switch on the provider locale.

Styling & tokens

  • Same trigger treatment as the workspace switcher: border-border, hover bg-nq-hover, open bg-nq-selected, focus nq-focus.
  • Target [data-slot=user-menu]. Extend the trigger with className.

Do / Don't

  • Do keep Settings in this menu instead of the sidebar footer. Support, docs and SidebarStatus may sit above the trigger.
  • Do use variant="avatar" at the end of AppHeader when the app has no sidebar.
  • Do pass onSignOut when the product has sessions; without it the menu simply ends after the preferences.
  • Don't put navigation to core pages here; those are sidebar items.
  • Don't hard-code the theme list; use the built-in submenu.

Lab

https://docs.nasaqui.com/?path=/docs/components-navigation-user-menu--docs

On this page