Skip to content

UserButton

<UserButton> renders the signed-in user’s initials as a button that opens a dropdown menu containing a “Manage profile” item, an optional language switcher, and sign-out. It’s the equivalent of the account menu in the top-right of most apps.

By default, “Manage profile” opens the full <UserProfile> widget in a modal, no wiring required. Switch to userProfileMode="navigation" if you’d rather route to your own account page.

The dropdown’s open/close state, the profile modal, click-outside, and keyboard navigation are handled inside the SDK runtime; you just place the component.

Place it inside <SignedIn>, since it requires an authenticated session.

import { SignedIn, UserButton } from '@torii-js/torii-react';
function Header({ profile }) {
return (
<SignedIn>
{/* Default: clicking "Manage profile" opens the profile modal. */}
<UserButton profile={profile} />
</SignedIn>
);
}

To route to your own account page instead of the modal:

<UserButton
profile={profile}
userProfileMode="navigation"
onManageProfile={() => navigate('/account')}
/>
Prop Type Default Description
profile UserProfileData | null null Used for the display name and initials. Falls back to the first 8 chars of the user ID when omitted.
userProfileMode 'modal' | 'navigation' 'modal' 'modal' opens <UserProfile> in a dialog. 'navigation' fires onManageProfile instead.
onManageProfile () => void n/a Called when “Manage profile” is clicked, in 'navigation' mode only. The item is hidden when omitted and not in modal mode.
showLanguage boolean auto Forwarded to the profile modal’s <UserProfile showLanguage> (modal mode only). Controls the Language row on the Profile section; defaults to auto (shown when more than one language is configured).
appearancePreference 'light' | 'dark' | 'system' n/a Forwarded to the profile modal’s Appearance preference; see <UserProfile>.
onAppearancePreferenceChange (value) => void n/a Forwarded alongside appearancePreference.
onActiveOrganizationChange (organizationId: string) => void - Forwarded to the profile modal’s Organizations section. Fires after the active organization changes from inside the modal, so a host with organization-scoped routes can leave a route that belonged to the previous one.
onOrganizationLeft (organizationId: string) => void - Forwarded to the profile modal’s Organizations section. Fires after the user leaves an organization.
variant 'icon' | 'expanded' 'icon' 'icon' shows just the avatar; 'expanded' shows an identity row (avatar plus display name and email) suited to sidebar footers and account bars.
className string n/a Extra class names for the trigger button.

Language switching moved. Earlier versions had a language switcher in this dropdown. It now lives in the <UserProfile> Profile section as a Language row, shown automatically when <ToriiProvider> is configured with more than one languages entry. UserButton no longer takes languages / currentLanguage / onLanguageChange.

When the environment has Multi-session enabled (dashboard: Authentication → Sessions, see session configuration), the dropdown grows an account switcher. There are no new props; it activates automatically from the environment config:

  • The menu lists the other accounts signed in on this browser (initials, display name, email); clicking one switches the active session.
  • An Add account item opens the standard <SignIn> card in a dialog. Signing in adds the account on this browser and makes it the active one; the previous account stays available in the switcher. The dialog carries the full card, so someone without an account can switch it to sign-up and finish there — that lands the same way a sign-in does.
  • A browser holds at most one session per account. Authenticating again as an account that is already signed in here replaces its session and makes it active rather than listing the person twice, so the switcher never offers a switch to the account you are already using. Other browsers and devices are unaffected.
  • Sign-out ends only the current account’s session and automatically switches to the most recently used remaining account; when none remain, the user lands signed out.

Switching accounts (and adding one) changes who is signed in. Because your app almost certainly cached data for the previous user, the SDK reloads the page by default after a swap — to signInUrl if set, otherwise / — so a fresh load rebuilds everything for the new account. To keep the swap in-page instead, set onActiveSessionChange on <ToriiProvider> and invalidate your own caches there. Initial sign-in and sign-out are unaffected.

To build your own switcher instead, use the headless useSessionList() hook.

  • Requires a provider: must be rendered within <ToriiProvider>; it reads signOut, user, and labels from context.
  • Sign-out: the menu’s sign-out item calls the SDK’s own signOut. Drive any post-sign-out routing off useAuth().isSignedIn flipping to false, or events.onSessionExpired. With multi-session enabled it only ends the current account’s session (see Account switcher).
  • Initials: derived from profile.name, then profile.email, then the fallback display name.
  • Powered by Torii: the dropdown shows a brand ribbon at its bottom edge, with the same visibility gating as the sign-in card footer (appearance.hideFooter, available on paid plans).

The trigger and menu slots (menuContent, menuItem, menuSeparator, destructiveButton) are themable via the appearance.elements prop on <ToriiProvider>. See elements.

import type { UserButtonProps } from '@torii-js/torii-react';