Skip to content
Torii docs

UserProfile

<UserProfile> is the full self-service account widget. It renders a card with a section sidebar covering the common “manage my account” surfaces:

  • Profile: edit name and profile details, preferred language (shown when more than one is configured), email addresses (add → verify → set-primary), and link/unlink OAuth connected accounts
  • Security: change password, set up two-factor authentication, view and revoke active devices, and delete the account
  • Privacy: GDPR data export request
  • Preferences: appearance (only when an appearance preference is wired up; hidden otherwise)

Everything is read off useAuth() and the SDK’s data hooks, so you don’t wire any fetching yourself.

The card can render two ways via the presentation prop: inline (the default, on a dedicated account page) or in a modal. Most apps never set this directly: <UserButton> opens the modal for you (userProfileMode="modal"). Drive presentation yourself only when you have a custom trigger.

Drop it inside <SignedIn> on an account/settings route. For a heading-and-layout version that embeds a <UserButton> too, use <UserDashboard>.

Inline, on an account page:

import { SignedIn, UserProfile } from '@torii-js/torii-react';
function AccountPage() {
return (
<SignedIn>
<UserProfile onUpdateSuccess={(p) => console.log('saved', p)} />
</SignedIn>
);
}

As a modal behind your own trigger:

const [open, setOpen] = useState(false);
<button onClick={() => setOpen(true)}>Account</button>
<UserProfile presentation="modal" open={open} onClose={() => setOpen(false)} />
PropTypeDefaultDescription
presentation'inline' | 'modal''inline''inline' renders the bare card; 'modal' wraps it in a dismissible dialog.
openboolean-Dialog visibility. Only used when presentation="modal".
onClose() => void-Called when the modal requests close (backdrop click, Escape, or the ✕ button).
showLanguagebooleanautoShow the Language row on the Profile section. Defaults to auto, shown when <ToriiProvider> has more than one languages entry. Pass false to hide it, true to force it.
appearancePreference'light' | 'dark' | 'system'-Current appearance (theme) choice. Together with onAppearancePreferenceChange, adds a Preferences section with an Appearance selector. Persistence is yours: store it per device (e.g. localStorage) or per user.
onAppearancePreferenceChange(value) => void-Called when the user picks a different appearance.
onUpdateSuccess(profile: UserProfileData) => void-Fired after a successful profile update.
onUpdateError(error: ToriiError) => void-Fired on a profile-update error. Branch on error.code; show error.message.
labelsPartial<ToriiSignupLabels>-Per-instance label overrides. Falls through to ToriiProvider labels.
classNamestring-Extra class names for the card.
  • Progressive disclosure: each row renders collapsed (a summary plus a single accent action like “Update profile” / ”+ Add email address”); clicking the action expands an inline form card in place with Cancel/confirm. Per-item actions (make primary, resend verification, remove, unlink, sign out of device) live in a ”⋯” menu on the item row.
  • Sign out of all other devices: the update-password card includes a checkbox (checked by default) that revokes every other session after a successful password change.
  • Requires a provider: reads profile, sessions, identities, and email addresses from <ToriiProvider> context.
  • Email addresses: the Profile section includes an email-address manager (wrapping useEmailAddresses). Users add an address, verify it via the emailed link, then set it primary; any verified address can sign in. The primary address can’t be removed.
  • OAuth link errors: if the user returns from a failed connected-account link (error captured from the URL fragment), the card opens the Profile section so the alert isn’t missed.
  • Privacy section: hosts the GDPR data export request.
  • Language row: appears on the Profile section when the provider has more than one language configured (or showLanguage={true}). The preference is synced to the user (user.locale), so it follows them across devices. The selector applies immediately: it switches the live UI language and persists the preference, with no Save step.
  • Appearance preference: pass appearancePreference + onAppearancePreferenceChange and a Preferences section appears with an Appearance selector (System / Light / Dark). Appearance is device-local by design: the component only renders the control; applying and persisting the theme is your app’s job.
  • Modal: locks body scroll, traps Tab focus, closes on Escape / backdrop click / ✕, and restores focus to the opener on close. Honours prefers-reduced-motion.

Honours the appearance prop on <ToriiProvider>. In modal mode the backdrop, panel, and close button expose the modalBackdrop, modalContent, and modalCloseButton element slots. See theming and elements.

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