Settings and profile
Account screens: a tabbed settings page and a public profile.
Installation & usage
npx @youj/cli add app-settingsAlso installs alert, alert-dialog, app-page, async-button, avatar, avatar-upload, badge, button, card, checkbox, dialog, dropdown-menu, field, icon-bell, icon-check, icon-credit-card, icon-download, icon-more-horizontal, icon-shield, icon-user, icon-user-plus, icon-users, input, input-group, password-input, presence-list, radio-group, segmented-control, select, skeleton, spotlight, switch, table, tabs, textarea, typography, use-controllable-state, use-mobile, youj-core, youj-ui-core.
The CLI copies the block to blocks/app/settings.tsx with every component it uses, so it’s yours to edit.
Every prop is optional and falls back to the demo, so it renders as you see it until you pass your own. Give it your data, rewrite or translate its strings through copy, and connect its actions:
'use client'
import { Settings, type SettingsProps } from '@/blocks/app/settings'
export function SettingsView({ user, members, roles, plans }: Pick<SettingsProps, 'user' | 'members' | 'roles' | 'plans'>) {
return (
<Settings
user={user}
members={members}
roles={roles}
plans={plans}
copy={{ title: 'Settings' }}
onTabChange={(tab) => {
// your code
}}
onRetry={() => {
// your code
}}
onSaveProfile={async (profile) => {
// await your API here; the block shows progress until it settles
}}
/>
)
}Description
A tabbed settings page that brings account, team, billing and notification preferences together; this story opens on the Profile tab.
A tabbed settings page that brings account, team, billing and notification preferences together; this story opens on the Profile tab.
Notification preferences as one card: a master Off / On, what to be told about, reminders and channels. Turning the master off mutes the rest, and nothing is stored until Save changes.
Notification preferences as one card: a master Off / On, what to be told about, reminders and channels. Turning the master off mutes the rest, and nothing is stored until Save changes.
A public profile for creators, with a cover, follow controls, tabs of work and a link visitors can copy.
A public profile for creators, with a cover, follow controls, tabs of work and a link visitors can copy.
Code
Settings, the Settings story: the files youj add writes.
blocks/app
Reference
Props36 props, 12 types
Props
| Prop | Type | |
|---|---|---|
defaultTab | stringThe tab open at first, when uncontrolled. default 'profile' | 'profile' |
tab | stringThe open tab, to control it. Pair with | – |
onTabChange | (tab: string) => voidCalled with the tab's id when the person switches tabs. | – |
sections | Array<SettingsSectionId | SettingsSection>The tabs, in order: a built-in id ( default the five built-in tabs | the five built-in tabs |
brand | { name: string; logo?: ReactNode }The workspace, named in the page's description, the team count and the invite, and its default Northwind Labs | Northwind Labs |
headingLevel | 1 | 2 | 3The page title's level. default 1 | 1 |
embedded | booleanA page in your app's frame: the shared page header (AppPage) and the frame's gutter, in a readable column centered in the content area, with no logo of its own. default true | true |
fill | booleanEmbedded, take the frame's whole width instead of stopping at a readable 1024px (at 100% scale). default false | false |
user | SettingsUserThe signed-in person: profile fields and account email. default Ada Lovelace | Ada Lovelace |
members | SettingsMember[]The team, in order. default the demo's four | the demo's four |
roles | SettingsRole[]The roles a member can hold; default Owner, Admin, Member, Viewer | Owner, Admin, Member, Viewer |
plans | SettingsPlan[]The plans, cheapest first. default Hobby, Pro, Enterprise | Hobby, Pro, Enterprise |
plan | stringThe current plan's id, to control it. | – |
defaultPlan | stringThe current plan's id at first, when uncontrolled. default 'pro' | 'pro' |
paymentMethod | SettingsPaymentMethod | nullThe card on file, or default a Visa ending 4242 | a Visa ending 4242 |
invoices | SettingsInvoice[]Past invoices, newest first. default the demo's three | the demo's three |
notifications | SettingsNotificationGroup[]Notification switches, by channel. default Email and Push | Email and Push |
loading | booleanShows skeleton rows in the team and invoice tables while data loads. default false | false |
copy | Partial<SettingsCopy>Any of the page's strings, to rewrite or translate. | – |
error | ReactNodeA load failure, shown above the tabs with a Retry button when | – |
onRetry | () => voidCalled from the error's Retry button. | – |
classNames | Partial<Record<'header' | 'tabs' | 'content', string>>Classes for key parts: the page header, the tab list and each tab's panel. | – |
onSaveProfile | (profile: SettingsProfile) => Promise<unknown> | unknownSaves the profile form; resolve when saved, throw to show the error. Default: a demo wait. | – |
onSaveAvatar | (file: File) => Promise<unknown> | unknownUploads a new photo. Default: a demo wait. | – |
onRemoveAvatar | () => Promise<unknown> | unknownRemoves the photo. Default: a demo wait. | – |
onUpdatePassword | (passwords: { current: string; next: string; }) => Promise<unknown> | unknownChanges the password once both new fields match. Default: a demo wait. | – |
onDeleteAccount | () => Promise<unknown> | unknownDeletes the account after the typed confirmation. Default: a demo wait. | – |
onInvite | (invite: { email: string; role: string; }) => Promise<unknown> | unknownSends an invite; the row joins the table once it resolves. Default: a demo wait. | – |
onRoleChange | (member: SettingsMember, role: string) => Promise<unknown> | unknownCalled when a member's role changes. | – |
onRemoveMember | (member: SettingsMember) => Promise<unknown> | unknownRemoves a member or revokes an invite; the row leaves once it resolves. | – |
onResendInvite | (member: SettingsMember) => Promise<unknown> | unknownSends a pending invite again. | – |
onChangePlan | (plan: SettingsPlan) => Promise<unknown> | unknownSwitches plan; the badge moves once it resolves. Default: a demo wait. | – |
onContactSales | (plan: SettingsPlan) => voidCalled from a plan marked | – |
onUpdatePayment | () => voidCalled from the payment method's Update button. | – |
onDownloadInvoice | (invoice: SettingsInvoice) => voidCalled from an invoice's download button. | – |
onNotificationChange | (notification: SettingsNotification, on: boolean) => voidCalled when a notification switch flips. | – |
NotificationOption
| Prop | Type | |
|---|---|---|
idRequired | string | – |
labelRequired | string | – |
description | string | – |
NotificationPreferencesValue
| Prop | Type | |
|---|---|---|
enabledRequired | booleanThe master switch: false mutes everything below it. | – |
whatRequired | stringThe id of the chosen "what" option. | – |
remindersRequired | string[]The ids of the ticked reminders. | – |
channelsRequired | string[]The ids of the ticked channels. | – |
SettingsSection
| Prop | Type | |
|---|---|---|
idRequired | string | – |
labelRequired | string | – |
icon | ReactNode | – |
panelRequired | ReactNodeThe tab's content. | – |
SettingsUser
| Prop | Type | |
|---|---|---|
nameRequired | string | – |
usernameRequired | string | – |
bioRequired | string | – |
emailRequired | string | – |
avatarUrl | stringTheir photo. Default: initials. | – |
verified | booleanShows the Verified badge beside the email. | – |
SettingsProfile
| Prop | Type | |
|---|---|---|
nameRequired | string | – |
usernameRequired | string | – |
bioRequired | string | – |
SettingsMember
| Prop | Type | |
|---|---|---|
idRequired | string | – |
nameRequired | string | – |
emailRequired | string | – |
roleRequired | stringOne of the | – |
invited | booleanInvited and not joined yet: shows a badge and offers resend or revoke. | – |
SettingsRole
| Prop | Type | |
|---|---|---|
valueRequired | string | – |
labelRequired | string | – |
SettingsPlan
| Prop | Type | |
|---|---|---|
idRequired | string | – |
nameRequired | string | – |
priceRequired | stringAs it reads, e.g. | – |
blurbRequired | string | – |
featuresRequired | string[] | – |
perMember | booleanPriced per member: adds | – |
contactSales | booleanSold by a conversation: the button reads | – |
SettingsPaymentMethod
| Prop | Type | |
|---|---|---|
brandRequired | stringe.g. | – |
last4Required | string | – |
expiresRequired | stringAs it reads, e.g. | – |
SettingsInvoice
| Prop | Type | |
|---|---|---|
idRequired | string | – |
dateRequired | stringAs it reads, e.g. | – |
amountRequired | stringAs it reads, e.g. | – |
statusRequired | SettingsInvoiceStatus'paid''open''refunded''failed' | – |
SettingsNotification
| Prop | Type | |
|---|---|---|
idRequired | string | – |
labelRequired | string | – |
descriptionRequired | string | – |
onRequired | booleanOn when the page opens. | – |
SettingsNotificationGroup
| Prop | Type | |
|---|---|---|
groupRequired | stringThe channel, e.g. | – |
itemsRequired | SettingsNotification[] | – |
Strings92 keys for copy
Strings
copy takes any of these keys; the rest keep their defaults. A key whose text holds a value (a count, a name) takes a function.
titledescriptiontabsLabelprofileTabaccountTabteamTabbillingTabnotificationsTabprofileTitleprofileDescriptionphotonameusernameusernamePrefixbiobioHintsaveProfilesavingsavedemailTitleemailDescriptionemailLabelverifiedpasswordTitlepasswordDescriptioncurrentPasswordnewPasswordconfirmPasswordpasswordMismatchupdatePasswordupdatingupdatedcheckFieldsdeleteTitledeleteDescriptiondeleteAccountdeleteConfirmTitledeleteConfirmDescriptiondeleteConfirmteamTitleteamCountmemberColumnroleColumnactionsColumninvitedBadgeroleForactionsForresendInviterevokeInviteremoveMemberemptyTeaminviteinviteTitleinviteDescriptioninviteEmailinviteEmailPlaceholderinviteRolecancelsendInvitesendinginvitedcheckEmailinvalidEmailcurrentPlanperMemberyourPlantalkToSalesdowngradeupgradeswitchingswitchedpaymentTitlepaymentDescriptioncardEndingcardExpiresnoPaymentMethodupdatePaymentinvoicesTitleinvoicesDescriptioninvoiceColumndateColumnamountColumnstatusColumndownloadColumndownloadInvoiceinvoiceStatusemptyInvoicesloadingerrorTitleretrynotificationsTitlenotificationsDescriptionAccessibilityheadings, tabs, forms, status
Accessibility
Settings and Profile use the kit’s Tabs, so the tab list is named, Left and Right Arrow move between tabs and the panel follows the selected one. Settings has one page heading (headingLevel changes it) and labelled fields and switches. The invite and confirm steps open in dialogs. Profile has a labelled aside and nav, the avatar is decorative (alt="") because the name sits beside it, and the activity heatmap is one image with a text label. Links and buttons are real a and button elements with the kit’s focus ring.