YuhuanStudioYunUIDocs
AI

Account Menu

The navbar account control — sign-in glyph, avatar once signed in, and a menu with identity, links and sign out.

The navbar account control: a sign-in glyph when signed out, the reader's avatar when signed in, and a menu carrying their identity, your links and a sign-out row.

Upstreamed from YunNEWS, which handles the signed-in swap better than the other apps. Purely presentational — you fetch the session, supply every label and own each action.

Import

tsx
1import { AccountMenu } from "@yuhuanowo/yunui/ai";

The three states

user is a three-state prop, and that is the whole point:

userRenders
undefineda fixed-size placeholder — the answer isn't known yet
nullthe sign-in glyph
an objectthe avatar (or a fallback glyph) plus the menu

A session cookie is usually httpOnly, so the page cannot read it and only the server can answer. While the answer is pending, guessing "signed out" and then swapping to an avatar makes every page load look like it signed the reader out — so this holds the space instead.

Signed out

Signed in

Click the avatar to open the menu.

Signed in

Wiring it up

tsx
1const [user, setUser] = useState<AccountMenuUser | null | undefined>(undefined);
2 
3useEffect(() => {
4 let alive = true;
5 api.me().then((d) => alive && setUser(d?.user ?? null));
6 return () => { alive = false; };
7}, []);
8 
9<AccountMenu
10 user={user}
11 signInHref="/login"
12 items={[{ key: "keys", label: t("apiKeys"), icon: KeyRound, href: "/account/keys" }]}
13 onSignOut={async () => { await api.logout(); setUser(null); router.refresh(); }}
14 labels={{ signIn: t("signIn"), signOut: t("signOut") }}
15/>

Omit onSignOut to hide the sign-out row. An item with onSelect renders as a button instead of a link.

Props

PropTypeDefaultDescription
classNamestring
itemsAccountMenuItem[][]Menu entries above the sign-out row.
labels{ signIn?: string; signOut?: string; menu?: string | undefined; fallbackName?: string | undefined; } | undefinedEvery string this renders — localize them yourself.
onSignOut(() => void)Called when the sign-out row is chosen. Omit to hide the row.
signInHref*stringWhere the signed-out button links.
user*AccountMenuUser | null | undefinedThe signed-in user, `null` when signed out, or `undefined` while the answer is still unknown. The three-state shape is the point: a session cookie is usually `httpOnly`, so the page cannot read it and only the server can answer. While it is `undefined` this renders a fixed-size placeholder rather than guessing — showing "sign in" first and swapping to an avatar makes every page load look like it signed the reader out.

On this page