Settings Page React block for Tailwind CSS v4
v1.0.0Added in 1.0.0
A React account settings page for a back office: profile, account, notifications, billing, security and a danger zone, with a save bar.
Pick a section in the left column (arrow keys move between them) or, with nav="tabs", in the tabs on top; on phones the sections are an iOS style list that pushes the section in with a back button and swipe back. Profile: upload a photo (crop, progress ring, remove), edit the name, title and a bio with a counter, the phone with its country, the language, a searchable time zone and the date format. Account: the email is read only with Verified; Change opens a dialog (a bottom sheet on phones) that asks for the new address and the current password, sends a 6 digit code (123456 passes, the sixth digit submits, Resend code waits 30 s) and then changes it. The workspace address checks itself when you leave the field (Checking…, then Available or Taken; "acme software" gets "Lowercase letters, digits and hyphens only"). Notifications: a switch per event and channel with a column toggle for all (one group per event on phones); switches save at once and flip back with a toast if the save fails. Quiet hours turn on with a switch and take two times (22:00 to 08:00 reads "next day"); the digest is a segmented choice. Billing: the plan with Change plan (a dialog to pick Start, Pro or Business with the monthly total) and Cancel (a confirmation; the plan then shows its end date and a way to resume it), the usage of users, AI tokens and storage, the card with Update, the company details with a CUI check and the address, and the invoices (cards on phones) with a download link each. Security: Change password opens a dialog with the strength meter and rules; Turn on starts a three step wizard: scan the QR code or copy the key, type the code (123456), then copy or download the ten backup codes; the badge On pops in and Turn off asks first. Revoke any other session or all of them at once; the current one cannot be revoked. Danger zone: Export counts up in a toast and then offers the file; Delete account asks you to type DELETE first. Any text change slides up the save bar with Discard and Save (mod+s); a failed save keeps the draft, shakes the bar and shows why, invalid fields turn red and the first one takes focus. Switching sections with unsaved changes asks first.
Settings Page is a Pro React block in the React blocks category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add settings-page, together with Settings Layout, Avatar Upload, Address Input, QR Code, Input and 31 more and the npm packages motion, lucide-react, react-hook-form and zod.
Add to a project
Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup
npx wingo-ui@latest add settings-pageSettings Page is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans
Usage
Import SettingsPage from @/components/blocks/settings-page.
// app/(admin)/settings/page.tsx (the shell lives in app/(admin)/layout.tsx: <AdminShell>{children}</AdminShell>)
"use client"
import { SettingsPage } from "@/components/blocks/settings-page"
export default function SettingsRoute() {
return (
<SettingsPage
onSave={async (section, values) => {
const res = await fetch(`/api/settings/${section}`, { method: "PUT", body: JSON.stringify(values) })
if (!res.ok) throw new Error("We could not save. Please try again.")
}}
onPreferenceChange={async (preference, value) => {
await fetch("/api/settings/preferences", { method: "PATCH", body: JSON.stringify({ preference, value }) })
}}
onTwoFactorChange={async (enabled) => {
await fetch("/api/security/2fa", { method: enabled ? "POST" : "DELETE" })
}}
/>
)
}Props
section"profil" | "cont" | "notificari" | "facturare" | "securitate" | "pericol"The open section, controlled; pair it with onSectionChange (a route per section).
defaultSectiondefault"profil""profil" | "cont" | "notificari" | "facturare" | "securitate" | "pericol"The section open on mount.
onSectionChange(section: SettingsPageSection) => voidCalled when another section opens (after the unsaved changes question).
sectionsdefault"all six"SettingsPageSection[]Which sections exist, in this order.
profileSettingsProfileEmma Carter's profile: photo, name, title, bio, phone, language, time zone, date format (SETTINGS_PAGE_SAMPLE.profile).
accountSettingsAccountThe email with its verified flag and the workspace name and address (SETTINGS_PAGE_SAMPLE.account).
notificationsSettingsNotificationPrefsEvent by channel switches, quiet hours and the digest (SETTINGS_PAGE_SAMPLE.notifications).
notificationEvents{ id: string; label: string; description?: string }[]The rows of the notifications grid: Overdue invoice, Payment received, Deal won, Mention, Task assigned, Weekly report.
channelsdefault"all three"("email" | "push" | "sms")[]The notification columns.
billingSettingsBillingPlan, renewal, seats, AI tokens, storage, the card, the company details and the invoices (SETTINGS_PAGE_SAMPLE.billing).
plansSettingsPlan[]The plans offered by Change plan: Start, Pro, Business with the price per user (SETTINGS_PAGE_SAMPLE.plans).
sessionsSettingsSession[]Signed in devices: MacBook Pro (current), iPhone 14, Windows (SETTINGS_PAGE_SAMPLE.sessions).
timeZones{ value: string; label: string; suggested?: boolean; keywords?: string[] }[]The time zone picker's options, suggested ones first (SETTINGS_PAGE_SAMPLE.timeZones).
takenSlugsstring[]Workspace addresses already in use, for the default availability check.
twoFactorEnabledbooleanTwo-step verification, controlled; pair it with onTwoFactorChange.
defaultTwoFactorEnableddefaultfalsebooleanTwo-step verification on at mount (On instead of Turn on).
onTwoFactorChange(enabled: boolean) => (void | Promise<unknown>)Turns two-step verification on (after the code checks out) or off (after the confirmation). Default: a simulated request.
twoFactorSecretdefault"JBSWY3DPEHPK3PXP"stringThe base32 key shown under the QR code, in groups of four, with a copy button.
twoFactorUridefault"otpauth://totp/Acme%20CRM:ana.pop%40acme.com?secret=JBSWY3DPEHPK3PXP&issuer=Acme%20CRM"stringThe otpauth:// address the QR code encodes.
backupCodesstring[]The ten backup codes of the last step (generated with a fixed seed in the sample).
verifyTwoFactorCode(code: string) => (boolean | Promise<boolean>)Checks the authenticator code. Default: 123456 passes.
passwordChangedAtDate | numberWhen the password last changed ("Last changed on Jun 12, 2026").
loginAlertsdefaulttruebooleanThe starting state of Alerte la autentificare.
verifyEmailCode(email: string, code: string) => (boolean | Promise<boolean>)Checks the code sent to the new email. Default: 123456 passes.
checkWorkspaceAddress(slug: string) => (boolean | Promise<boolean>)Whether a workspace address is free; runs when the field loses focus and before a save. Default: takenSlugs after 600 ms.
navdefault"sidebar""sidebar" | "tabs"The section navigation from 768px: a left column or tabs on top.
saveBarPositiondefault"sticky""sticky" | "fixed"Where the save bar sits: at the bottom of the content column, or pinned to the window. Phones always pin it.
saveShortcutdefault"mod+s"stringSaves the open section while it has changes; "" turns the key off.
confirmLeavedefaulttruebooleanAsks before switching sections with unsaved changes.
resendSecondsdefault30numberHow long Retrimite codul waits in the email dialog.
defaultDialogdefault"none""none" | "email" | "password" | "two-factor" | "plan" | "cancel-plan" | "delete"Opens with this dialog on desktop; the section that owns it has to be the one open (email in cont, password and two-factor in securitate, plan and cancel-plan in facturare, delete in pericol).
defaultProfileDraftPartial<SettingsProfileDraft>Edits applied to the profile form on mount, so it opens with unsaved changes.
onSave(section: SettingsFormSection, values: SettingsSaveValues[SettingsFormSection]) => (void | Promise<unknown>)Saves the open section's text fields from the save bar (profil, cont, notificari, facturare). A rejection keeps the draft and shows its message in the bar. Default: a simulated request.
onPreferenceChange(preference: string, value: boolean) => (void | Promise<unknown>)Switches that save on their own: "notificari.matrix.<event>.<channel>", "notificari.matrix.*.<channel>", "notificari.quietHours", "securitate.loginAlerts". A rejection flips the switch back with a toast.
onUpload(blob: Blob, context: { file; signal; onProgress }) => Promise<string | void>Uploads the cropped photo; resolve the new url. Default: a pretend upload with progress that keeps the local preview.
onEmailChange(email: string, currentPassword: string) => (void | Promise<unknown>)Runs after the code for the new address checks out.
onPasswordChange(values: { currentPassword: string; newPassword: string }) => (void | Promise<unknown>)The password dialog's submit; a rejection shows its message in the dialog.
onSessionRevoke(session: SettingsSession) => (void | Promise<unknown>)Signs a device out (once per device for Sign out all others).
onExport() => (void | Promise<unknown>)Export your data. Default: a toast that counts up, then offers a JSON download.
onDeleteAccount() => (void | Promise<unknown>)Runs after the typed confirmation.
onPlanChange(planId: string | null) => (void | Promise<unknown>)A plan id switches (or resumes); null cancels at the end of the period.
onDirtyChange(dirty: boolean) => voidThe open section has unsaved changes (hide a phone tab bar while true, one bar per edge).
paymentMethodHrefdefault"/settings/billing/card"stringWhere Update on the card goes.
labelsdefault"DEFAULT_SETTINGS_PAGE_LABELS"Partial<SettingsPageLabels>Every visible string, merged over the English DEFAULT_SETTINGS_PAGE_LABELS. Nested keys carry the composed items' strings (validation, avatarUpload, cropper, phoneInput, timePicker, select, addressInput, qrCode, table, list, usageMeter).
localedefault"en-US"stringIntl locale for numbers, money, dates and relative times.
currencydefault"USD"stringThe currency of the plan prices and the invoices.
nowDate | numberThe reference time for the sessions and the date format sample; default the live clock.
tonedefault"neutral""neutral" | "brand" | "success" | "warning" | "danger" | "info"Accent of the section navigation, the switches, the primary buttons and the save button.
radiusdefault"md""sm" | "md" | "lg"Corner size of the settings groups (12 / 16 / 24px).
loadingdefaultfalsebooleanThe open section as skeleton rows in the real layout.
animateIndefaulttruebooleanThe page rises in once when it mounts on the client; off in thumbnails and under reduced motion.
linkComponentdefault"<a>"(props: LinkComponentProps) => ReactNodeThe router link for the card and invoice links; default the surrounding LinkProvider's (the admin shell's).
classNamestringClasses for the root.
classNamesPartial<Record<"layout" | "section" | "saveBar", string>>Classes for the settings layout, every settings group and the save bar.
failNextSavedefaultfalsebooleanThe built-in pretend save (no onSave) fails once, so the error in the bar and the kept draft can be seen and tested.
Parts
DEFAULT_SETTINGS_PAGE_LABELS
constantEvery English string of the page, including the nested strings of the composed items (validation, avatar upload, cropper, phone input, time picker, table). Spread it and override what you translate.
SETTINGS_PAGE_LABELS_EN
constantAn alias of DEFAULT_SETTINGS_PAGE_LABELS, kept so imports that name the English set keep working.
ProfileSection
componentThe Profile section on its own: photo, name, title, bio, phone, language, time zone and date format. Takes { ctx: SettingsSectionContext }, the state SettingsPage builds; use it when you compose your own page.
AccountSection
componentThe Account section on its own: the verified email with its change dialog and the workspace address check. Takes { ctx }.
NotificationsSection
componentThe Notifications section on its own: a switch per event and channel, quiet hours and the digest. Takes { ctx }.
BillingSection
componentThe Billing section on its own: the plan with change and cancel dialogs, usage meters, the card, company details and invoices. Takes { ctx }.
SecuritySection
componentThe Security section on its own: password change, the two-factor setup wizard with backup codes, and the session list. Takes { ctx }.
DangerSection
componentThe danger zone on its own: data export with progress and account deletion that asks you to type DELETE. Takes { ctx }.
SectionSkeleton
componentThe loading rows of a section in its real layout, the same ones loading shows. Takes { ctx, section }.
SETTINGS_PAGE_SAMPLE
constantThe demo data the page renders without props: a profile, account, notification preferences, plans, billing, sessions, time zones and two-factor setup. Replace each piece with your own through the matching prop.
SETTINGS_PAGE_SAMPLE_EN
constantAn alias of SETTINGS_PAGE_SAMPLE, kept for imports that name the English sample.
SETTINGS_PAGE_NOW
constantThe fixed clock of the sample (Thursday, Sep 24, 2026, 4:40 PM), so session times and screenshots never drift.
SETTINGS_PAGE_SECTIONS
constantThe section ids in order: profil, cont, notificari, facturare, securitate, pericol. Use them for section and onSectionChange.
SETTINGS_CHANNELS
constantThe notification channels of the sample, as columns of the preferences grid: email, push and sms.
generateBackupCodes
functionSeeded demo backup codes in the XXXX-XXXX format, the same on every render. For screenshots and tests only; generate real codes on your server.
countdefault10numberHow many codes.
seeddefault2026numberThe random seed; the same seed gives the same codes.
returnsstring[]The codes.
totpUri
functionBuilds the otpauth:// URI the two-factor QR code encodes, for an account, a base32 secret and an issuer.
account*stringThe account name shown in the authenticator app, usually the email.
secretstringThe base32 secret; defaults to the sample's.
issuerstringThe app name shown in the authenticator; defaults to the sample's.
returnsstringThe otpauth://totp/... URI.
SettingsSectionContext
typeThe state a section receives as ctx: labels, locale, currency, tone, the data and the save handlers.
Examples
Notifications
Events by channel with a toggle per column, quiet hours from 22:00 to 08:00 and the digest.
Billing
The Pro plan with its usage, the card, the company details with the address and the invoices.
Two-step verification setup
defaultDialog="two-factor": step 1 of the wizard with the QR code and the key; 123456 passes step 2.
Unsaved profile
defaultProfileDraft changes the name and the title: the save bar offers Discard and Save (mod+s).
Delete the account
defaultDialog="delete": the button unlocks once you type DELETE.
Loading
loading: the section as skeleton rows under the navigation.
Brand tone, tabs
tone="brand", radius="lg", nav="tabs" on Security with two-step verification on.
British English
locale="en-GB": dates and numbers follow the locale.
Dependencies
Files
- components/blocks/settings-page.tsx
- components/blocks/settings-page-sections.tsx
- components/blocks/settings-page-data.ts
FAQ
Is the React Settings Page block free?
The preview, props and docs are free; copying the source needs a Pro plan. See plans.
How do I install Settings Page?
Run npx wingo-ui@latest add settings-page. It also adds the Wingo UI items it builds on (Settings Layout, Avatar Upload, Address Input, QR Code, Input and 31 more) and the npm packages motion, lucide-react, react-hook-form and zod. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/settings-page.
How does Settings Page behave on phones?
Pick a section in the left column (arrow keys move between them) or, with nav="tabs", in the tabs on top; on phones the sections are an iOS style list that pushes the section in with a back button and swipe back.
See also
More React blocks
Articles using this component
- Shadcn Profile Page in React: Follow, Tabs and Edit Sheet
Build it: screens and apps9 min read
- React Settings Page: Section Nav, Save Bar, Danger Zone
Build it: screens and apps11 min read
- Codex MCP Setup: Build React UI With Real Components
Building UI with AI agents11 min read
- Nextjs Admin Dashboard Tutorial: 5 Screens, Phone-Ready
Build it: screens and apps23 min read