@col/user-menu
Versie: 1.1.0 Toegevoegd: 2026-08-03
Herkomst
Geëxtraheerd uit supplier-onboarding-vercel/src/components/dashboard/nav.tsx
(regels ~140-166), het gebruikersmenu rechtsboven in de dashboard-nav: een knop
met naam en pijltje die een dropdown opent met e-mailadres, een link naar het
profiel en uitloggen.
Waarvoor
Het gebruikersmenu voor de rechterbovenhoek van een ingelogde app: een
Button met de naam en een pijltje, die bij een klik een dropdown opent. De
dropdown toont optioneel een e-mailkop en daaronder een lijst instelbare
acties — meestal "Profiel" en "Uitloggen", maar de app bepaalt zelf wat erin
staat.
Gebruik het niet voor een menu met submenu's of zoekfunctie — dit is bewust een platte lijst van acties, geen navigatiestructuur.
Wat je app moet leveren
| Prop | Type | Betekenis |
|---|---|---|
name |
string |
Getoond op de knop. Meestal de naam, met het e-mailadres als terugval wanneer er geen naam bekend is. Verplicht. |
email |
string? |
Getoond als kop bovenin het menu. Weglaten betekent geen kop. |
items |
UserMenuItem[] |
De acties in het menu. Verplicht (mag leeg zijn). |
align |
'start' | 'end'? |
Uitlijning van het menu ten opzichte van de knop. Default 'end'. |
UserMenuItem:
| Veld | Type | Betekenis |
|---|---|---|
label |
string |
Tekst van het item. |
icon |
ReactNode? |
Icoon links van het label, bijvoorbeeld een Lucide-icoon. |
onSelect |
() => void |
Aangeroepen bij een klik op het item. |
variant |
'default' | 'destructive'? |
'destructive' kleurt het item rood — voor uitloggen. Krijgt automatisch een scheidingslijn ervoor als er items boven staan. |
Voorbeeld:
<UserMenu
name={user.name ?? user.email}
email={user.email}
items={[
{ label: 'Profiel', icon: <User className="h-4 w-4" />, onSelect: () => router.push('/profile') },
{ label: 'Uitloggen', onSelect: () => signOut(), variant: 'destructive' },
]}
/>
Bestanden
| Bestand | Landt in | Soort |
|---|---|---|
user-menu.tsx |
components/nav/ |
beheerd |
Upstream shadcn-afhankelijkheden: button, dropdown-menu. Geen cssVars.
Gebruikt door
| App | Sinds versie | Opmerkingen |
|---|---|---|
| — | — | Nog geen consumers. supplier-onboarding-vercel is de bron van dit patroon en draait nog op zijn eigen kopie in src/components/dashboard/nav.tsx; die kan hierop over wanneer het uitkomt. |
Bewuste keuzes
- De trigger is met
cn(buttonVariants({ … }), …)gestyled, geen<Button asChild>erin (v1.1.0).asChildbestaat niet in Base UI, en twee van de vijf consumers draaien daarop. Zie regel 5 inAGENTS.md. text-destructivein plaats van het hardgecodeerdetext-red-600uit de bron.destructivehoort bij elke shadcn-installatie en respecteert dark mode, dus dit item heeft geen eigen tokens nodig.- De scheidingslijn voor een destructive item is automatisch, niet een
aparte prop. Zodra een item
variant: 'destructive'heeft en er items voor staan, verschijnt deDropdownMenuSeparatorvanzelf — consistent met hoe de bron het gebruikte (altijd een separator vóór "Uitloggen"). - Geen
useSession, geen routing, geen i18n. De bron haaldeuser.nameuit de sessie, navigeerde metuseRouter()en vertaalde labels metuseLanguage(). Dat is er allemaal uit: dit item krijgt kant-en-klare strings en callbacks via props, zodat het los werkt van NextAuth, Next.js routing en een specifiek i18n-systeem.
Bekende beperkingen
- Geen ingebouwd avatar of profielfoto — alleen tekst op de trigger. Een variant met avatar is nog niet gevraagd.
itemsondersteunt geen geneste submenu's; voor complexere menu's is dit component niet het juiste startpunt.
Zie ook
Voor een app met een zijbalk in plaats van een bovenbalk: @col/user-panel
— het gebruikersblok linksonder, met avatar, controls-slot en een
action-slot in plaats van een dropdown. Zie de vergelijkingstabel in
docs/items/user-panel.md.