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.
When to use
Section titled “When to use”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)} />| Prop | Type | Default | Description |
|---|---|---|---|
presentation | 'inline' | 'modal' | 'inline' | 'inline' renders the bare card; 'modal' wraps it in a dismissible dialog. |
open | boolean | - | Dialog visibility. Only used when presentation="modal". |
onClose | () => void | - | Called when the modal requests close (backdrop click, Escape, or the ✕ button). |
showLanguage | boolean | auto | Show 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. |
labels | Partial<ToriiSignupLabels> | - | Per-instance label overrides. Falls through to ToriiProvider labels. |
className | string | - | Extra class names for the card. |
Behaviour
Section titled “Behaviour”- 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+onAppearancePreferenceChangeand 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.
Theming
Section titled “Theming”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.
TypeScript
Section titled “TypeScript”import type { UserProfileProps } from '@torii-js/torii-react';