Templates
Account menu
A menu opened by the avatar and name at the end of the top bar; profile and settings links, workspace and theme submenus, help and sign-out.
The account menu gathers the person’s own links and preferences in one place. The AppShell template puts it at the very end of the top bar; on narrow screens the name hides and the avatar stays.
Preview
Section titled “Preview”Press the name at the end of the top bar. Move with the arrow keys; the right arrow opens the “Workspace” and “Theme” submenus. In the demo, “Sign out” shows a toast. The brand and mode switches in the page header restyle the preview too.
pnpm add @bigbang/ui| Data | Type | Note |
|---|---|---|
| Person | { name, email } |
The name on the button and avatar, the email as the group label. |
| Workspace | string |
When it changes, the app opens that workspace; the demo shows a toast. |
onSignOut |
() => void |
The app signs out. |
import { Avatar, Button, DropdownMenu, Icon, useToast } from '@bigbang/ui';import { useState } from 'react';import type { Lang } from '../../patterns/lang';
const copy = { tr: { name: 'Kullanıcı A', trigger: 'Hesap menüsü: Kullanıcı A', account: 'kullanici.a@ornek.com', profile: 'Profil', settings: 'Ayarlar', workspace: 'Çalışma alanı', workspaces: ['Çalışma alanı 1', 'Çalışma alanı 2'], switched: (name: string) => `${name} açıldı.`, theme: 'Tema', themes: { light: 'Açık', dark: 'Koyu', system: 'Sistem' }, help: 'Yardım', signOut: 'Çıkış yap', signedOut: 'Oturum kapatıldı.', }, en: { name: 'User A', trigger: 'Account menu: User A', account: 'user.a@example.com', profile: 'Profile', settings: 'Settings', workspace: 'Workspace', workspaces: ['Workspace 1', 'Workspace 2'], switched: (name: string) => `${name} opened.`, theme: 'Theme', themes: { light: 'Light', dark: 'Dark', system: 'System' }, help: 'Help', signOut: 'Sign out', signedOut: 'Signed out.', },};
export type AccountMenuProps = { lang?: Lang; /** Opens the menu on first render. */ defaultOpen?: boolean; /** Runs on "Sign out". The demo shows a toast. */ onSignOut?: () => void;};
/** * The account menu at the end of the app header: the person's avatar and name open a DropdownMenu * with profile and settings links, a workspace submenu, a theme choice, help and sign-out. */export function AccountMenu({ lang = 'tr', defaultOpen = false, onSignOut }: AccountMenuProps) { const t = copy[lang]; const toast = useToast(); const [workspace, setWorkspace] = useState(t.workspaces[0] ?? ''); const [theme, setTheme] = useState('system'); return ( <DropdownMenu align="end" defaultOpen={defaultOpen} trigger={ <Button variant="tertiary" size="sm" aria-label={t.trigger} startIcon={<Avatar name={t.name} size="xs" decorative />} endIcon={<Icon name="chevron-down" />}> <span className="hidden sm:inline">{t.name}</span> </Button> } > <DropdownMenu.Group label={t.account}> <DropdownMenu.LinkItem href="#" icon="user"> {t.profile} </DropdownMenu.LinkItem> <DropdownMenu.LinkItem href="#" icon="settings"> {t.settings} </DropdownMenu.LinkItem> </DropdownMenu.Group> <DropdownMenu.Separator /> <DropdownMenu.Submenu label={t.workspace} icon="layout-grid"> <DropdownMenu.RadioGroup label={t.workspace} value={workspace} onValueChange={(value) => { setWorkspace(value); toast.show({ title: t.switched(value) }); }} > {t.workspaces.map((name) => ( <DropdownMenu.RadioItem key={name} value={name}> {name} </DropdownMenu.RadioItem> ))} </DropdownMenu.RadioGroup> </DropdownMenu.Submenu> <DropdownMenu.Submenu label={t.theme} icon="sun"> <DropdownMenu.RadioGroup label={t.theme} value={theme} onValueChange={setTheme}> {(['light', 'dark', 'system'] as const).map((value) => ( <DropdownMenu.RadioItem key={value} value={value}> {t.themes[value]} </DropdownMenu.RadioItem> ))} </DropdownMenu.RadioGroup> </DropdownMenu.Submenu> <DropdownMenu.LinkItem href="#" icon="circle-help"> {t.help} </DropdownMenu.LinkItem> <DropdownMenu.Separator /> <DropdownMenu.Item icon="log-out" onSelect={onSignOut ?? (() => toast.show({ title: t.signedOut }))}> {t.signOut} </DropdownMenu.Item> </DropdownMenu> );}Structure
Section titled “Structure”- Trigger: a
tertiaryButton with a decorative Avatar first and a down chevron last. - DropdownMenu (
align="end"). - A group labelled with the email: Profile and Settings links (
DropdownMenu.LinkItem). - “Workspace” and “Theme” submenus, each a single-choice
RadioGroup. - A Help link, a separator and “Sign out” last.
Motion
Section titled “Motion”The menu fades and scales in under the trigger with motion.popover; submenus open beside it. With reduced motion only a short fade stays.
Accessibility
Section titled “Accessibility”- The trigger is named “Account menu: User A”; the visible name is part of it (label in name). The avatar is
decorative, so the name is not read twice. - The menu has the
menurole; arrow keys, Home/End and typing a letter move through it. Submenu items carryaria-haspopup="menu"; the right arrow opens and the left arrow closes them. - Theme and workspace options are
menuitemradio; the chosen one is read througharia-checked. - Escape closes the menu and returns focus to the trigger; choosing an item returns focus there too.
- Links are real
aelements, so they open in a new tab.
Components used
Section titled “Components used”DropdownMenu, Avatar, Button, Icon, Toast.