Skip to content

Settings and profile

Account screens: a tabbed settings page and a public profile.

Installation & usage

npx @youj/cli add app-settings

Also 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:

settings-view.tsx
'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
      }}
    />
  )
}

Reference

Props36 props, 12 types

Props

Settings props
PropType
defaultTabstring

The tab open at first, when uncontrolled.

default 'profile'

'profile'
tabstring

The open tab, to control it. Pair with onTabChange.

–
onTabChange(tab: string) => void

Called with the tab's id when the person switches tabs.

–
sectionsArray<SettingsSectionId | SettingsSection>

The tabs, in order: a built-in id ('profile' | 'account' | 'team' | 'billing' | 'notifications') or your own { id, label, icon, panel }.

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 logo over the standalone title.

default Northwind Labs

Northwind Labs
headingLevel1 | 2 | 3

The page title's level.

default 1

1
embeddedboolean

A 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
fillboolean

Embedded, take the frame's whole width instead of stopping at a readable 1024px (at 100% scale).

default false

false
userSettingsUser

The signed-in person: profile fields and account email.

default Ada Lovelace

Ada Lovelace
membersSettingsMember[]

The team, in order.

default the demo's four

the demo's four
rolesSettingsRole[]

The roles a member can hold; owner rows are locked.

default Owner, Admin, Member, Viewer

Owner, Admin, Member, Viewer
plansSettingsPlan[]

The plans, cheapest first.

default Hobby, Pro, Enterprise

Hobby, Pro, Enterprise
planstring

The current plan's id, to control it.

–
defaultPlanstring

The current plan's id at first, when uncontrolled.

default 'pro'

'pro'
paymentMethodSettingsPaymentMethod | null

The card on file, or null for none.

default a Visa ending 4242

a Visa ending 4242
invoicesSettingsInvoice[]

Past invoices, newest first.

default the demo's three

the demo's three
notificationsSettingsNotificationGroup[]

Notification switches, by channel.

default Email and Push

Email and Push
loadingboolean

Shows skeleton rows in the team and invoice tables while data loads.

default false

false
copyPartial<SettingsCopy>

Any of the page's strings, to rewrite or translate.

–
errorReactNode

A load failure, shown above the tabs with a Retry button when onRetry is set.

–
onRetry() => void

Called from the error's Retry button.

–
classNamesPartial<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> | unknown

Saves the profile form; resolve when saved, throw to show the error. Default: a demo wait.

–
onSaveAvatar(file: File) => Promise<unknown> | unknown

Uploads a new photo. Default: a demo wait.

–
onRemoveAvatar() => Promise<unknown> | unknown

Removes the photo. Default: a demo wait.

–
onUpdatePassword(passwords: { current: string; next: string; }) => Promise<unknown> | unknown

Changes the password once both new fields match. Default: a demo wait.

–
onDeleteAccount() => Promise<unknown> | unknown

Deletes the account after the typed confirmation. Default: a demo wait.

–
onInvite(invite: { email: string; role: string; }) => Promise<unknown> | unknown

Sends an invite; the row joins the table once it resolves. Default: a demo wait.

–
onRoleChange(member: SettingsMember, role: string) => Promise<unknown> | unknown

Called when a member's role changes.

–
onRemoveMember(member: SettingsMember) => Promise<unknown> | unknown

Removes a member or revokes an invite; the row leaves once it resolves.

–
onResendInvite(member: SettingsMember) => Promise<unknown> | unknown

Sends a pending invite again.

–
onChangePlan(plan: SettingsPlan) => Promise<unknown> | unknown

Switches plan; the badge moves once it resolves. Default: a demo wait.

–
onContactSales(plan: SettingsPlan) => void

Called from a plan marked contactSales.

–
onUpdatePayment() => void

Called from the payment method's Update button.

–
onDownloadInvoice(invoice: SettingsInvoice) => void

Called from an invoice's download button.

–
onNotificationChange(notification: SettingsNotification, on: boolean) => void

Called when a notification switch flips.

–

NotificationOption

NotificationOption props
PropType
idRequiredstring–
labelRequiredstring–
descriptionstring–

NotificationPreferencesValue

NotificationPreferencesValue props
PropType
enabledRequiredboolean

The master switch: false mutes everything below it.

–
whatRequiredstring

The id of the chosen "what" option.

–
remindersRequiredstring[]

The ids of the ticked reminders.

–
channelsRequiredstring[]

The ids of the ticked channels.

–

SettingsSection

SettingsSection props
PropType
idRequiredstring–
labelRequiredstring–
iconReactNode–
panelRequiredReactNode

The tab's content.

–

SettingsUser

SettingsUser props
PropType
nameRequiredstring–
usernameRequiredstring–
bioRequiredstring–
emailRequiredstring–
avatarUrlstring

Their photo. Default: initials.

–
verifiedboolean

Shows the Verified badge beside the email.

–

SettingsProfile

SettingsProfile props
PropType
nameRequiredstring–
usernameRequiredstring–
bioRequiredstring–

SettingsMember

SettingsMember props
PropType
idRequiredstring–
nameRequiredstring–
emailRequiredstring–
roleRequiredstring

One of the roles values.

–
invitedboolean

Invited and not joined yet: shows a badge and offers resend or revoke.

–

SettingsRole

SettingsRole props
PropType
valueRequiredstring–
labelRequiredstring–

SettingsPlan

SettingsPlan props
PropType
idRequiredstring–
nameRequiredstring–
priceRequiredstring

As it reads, e.g. $20 or Custom.

–
blurbRequiredstring–
featuresRequiredstring[]–
perMemberboolean

Priced per member: adds copy.perMember after the price.

–
contactSalesboolean

Sold by a conversation: the button reads copy.talkToSales and calls onContactSales.

–

SettingsPaymentMethod

SettingsPaymentMethod props
PropType
brandRequiredstring

e.g. Visa.

–
last4Requiredstring–
expiresRequiredstring

As it reads, e.g. 08 / 2028.

–

SettingsInvoice

SettingsInvoice props
PropType
idRequiredstring–
dateRequiredstring

As it reads, e.g. Sep 1, 2026.

–
amountRequiredstring

As it reads, e.g. $240.00.

–
statusRequiredSettingsInvoiceStatus
'paid''open''refunded''failed'
–

SettingsNotification

SettingsNotification props
PropType
idRequiredstring–
labelRequiredstring–
descriptionRequiredstring–
onRequiredboolean

On when the page opens.

–

SettingsNotificationGroup

SettingsNotificationGroup props
PropType
groupRequiredstring

The channel, e.g. Email.

–
itemsRequiredSettingsNotification[]–
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.

titledescriptiontabsLabelprofileTabaccountTabteamTabbillingTabnotificationsTabprofileTitleprofileDescriptionphotonameusernameusernamePrefixbiobioHintsaveProfilesavingsavedemailTitleemailDescriptionemailLabelverifiedpasswordTitlepasswordDescriptioncurrentPasswordnewPasswordconfirmPasswordpasswordMismatchupdatePasswordupdatingupdatedcheckFieldsdeleteTitledeleteDescriptiondeleteAccountdeleteConfirmTitledeleteConfirmDescriptiondeleteConfirmteamTitleteamCountmemberColumnroleColumnactionsColumninvitedBadgeroleForactionsForresendInviterevokeInviteremoveMemberemptyTeaminviteinviteTitleinviteDescriptioninviteEmailinviteEmailPlaceholderinviteRolecancelsendInvitesendinginvitedcheckEmailinvalidEmailcurrentPlanperMemberyourPlantalkToSalesdowngradeupgradeswitchingswitchedpaymentTitlepaymentDescriptioncardEndingcardExpiresnoPaymentMethodupdatePaymentinvoicesTitleinvoicesDescriptioninvoiceColumndateColumnamountColumnstatusColumndownloadColumndownloadInvoiceinvoiceStatusemptyInvoicesloadingerrorTitleretrynotificationsTitlenotificationsDescription
Built from26 components
Accessibilityheadings, 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.