Skip to content

Settings Section

The repeating unit of a settings page: a title and description on the left, a card with the content on the right, and a Save and Cancel bar that appears only when something has changed. Use SettingsRow inside for toggle lists. Your onSave does the work. UI permission is not security: the server must check again.

Blockv0.1.0experimentalWCAG 2.2 AAView spec

A ready-made piece, built from the library's own parts.

A block puts several components together into something you would otherwise assemble by hand. It never fetches data: you give it the data, or answer its callbacks. It is copied into your project like any component, with the parts it uses, so you can change anything.

Basic

Full screen (opens in a new tab)

Profile

Your name and the email address we write to.

 

Stacked

Full screen (opens in a new tab)

Company

Shown on your invoices.

Optional.

 

Split

Full screen (opens in a new tab)

Company

Shown on your invoices.

Optional.

 

Toggles

Full screen (opens in a new tab)

Notifications

Choose what we email you about.

Weekly summaryA short email every Monday with what changed.
InvoicesWhen a new invoice is ready.
Product newsNew features, once or twice a month.

Danger

Full screen (opens in a new tab)

Delete workspace

This removes the workspace and everything in it for all members.

Deleted workspaces cannot be restored.

States

Full screen (opens in a new tab)

Billing email

Try saving a changed address: the server refuses it.

 

Time zone

Try saving a change: the server is unavailable.

 

Permissions

Full screen (opens in a new tab)

Company

Shown on your invoices.

Only owners can change company details.

 

ClassNames

Full screen (opens in a new tab)

Display name

How your name appears to others.

 

Settings page

Full screen (opens in a new tab)

Settings

Manage your profile and how we contact you.

Profile

Your name and the email address we write to.

 

Notifications

Choose what we email you about.

Weekly summaryA short email every Monday.
InvoicesWhen a new invoice is ready.
Product newsNew features, once or twice a month.

Delete account

Removes your account and your personal data.

This cannot be undone.

Installation

npx rdloom add settings-section

Copies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes.

Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/settings-section.json

Works, but without upgrade tracking.

Usage

import { FormTextField, SettingsSection } from "@rdloom/react";

<div className="flex w-full justify-center">
  <div className="w-full max-w-4xl">
    <SettingsSection
      title="Profile"
      description="Your name and the email address we write to."
      defaultValues={{ name: "Lena Fischer", email: "lena.fischer@example.com" }}
      onSave={async () => {
        await wait(600);
      }}
    >
      <div className="flex flex-col gap-4">
        <FormTextField name="name" label="Name" isRequired />
        <FormTextField name="email" label="Email" type="email" isRequired />
      </div>
    </SettingsSection>
  </div>
</div>

API Reference

Defined by the spec. Components also accept the props of the React Aria component they wrap.

PropTypeDefault
titlerequired

The section's heading, e.g. "Profile".

stringnone
description

One or two sentences on what the section controls.

stringnone
headingLevel

Heading level of the title, 2 to 6.

number2
children

The content of the card: form fields (when onSave is set they are connected to the section's form), SettingsRow lines, or any content.

nodenone
orientation

stacked puts the title and description above the card, full width. split puts them in a left column beside the card from the md breakpoint up and stacks them on a phone.

"stacked" | "split""stacked"
tone

danger marks a section with destructive actions: a danger-colored border and title. The color is never the only signal: say it in the title.

"default" | "danger""default"
defaultValues

The starting values of the section's form. Needed with onSave. Fields inside are connected by name (FormTextField, FormSwitch, Field).

Record<string, any>none
onSave

Saves the changed values; yours, async. Resolve for success. Return { fieldErrors } or { formError } to show a problem and keep the changes. Without onSave the section has no footer.

(values: Record<string, any>) => void | SubmitResult | Promise<void | SubmitResult>none
onCancel

Called after the person discarded their changes with Cancel.

() => voidnone
saveLabel

The text of the save button.

string"Save changes"
successMessage

The status message shown and announced after a save that worked.

string"Changes saved"
permissions

What the app allows: edit. Disabled makes the content read-only: every field inside is disabled and the reason is shown above the content and linked to it. Hidden renders nothing; disabled keeps the control reachable (aria-disabled) with the reason shown and read, and nothing runs. This only changes what people see: the server must check again.

Permissions<"edit">none
classNames

Extra class names for single parts, so you can restyle one part without editing the file. Keys: root, header, title, description, card, content, footer, saveButton, cancelButton, reason, status.

Partial<Record<"root" | "header" | "title" | "description" | "card" | "content" | "footer" | "saveButton" | "cancelButton" | "reason" | "status", string>>none

Accessibility

Role region, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.

Keyboard

  • Tab: moves through the fields, then Cancel and Save changes when they are shown
  • Enter in a text field: saves

Screen readers announce

  • "Profile, region"
  • "Unsaved changes" when the first change is made
  • "Save changes, button"
  • "Changes saved" after saving

What your code must do

  • The section is a region named by its heading, so it can be reached from a landmark list
  • The Save and Cancel bar appears only when a value differs from the last saved one; a polite status says "Unsaved changes" when it appears
  • After a save that worked a status says the success message and focus moves to it, because the Save button has gone
  • Cancel puts the saved values back and moves focus to the first field
  • A failed save keeps the changes, moves focus to the error summary and links each problem to its field
  • When editing is not allowed every field is disabled and the reason is visible text linked to the content with aria-describedby

Block contract

Data
The starting values of the section's form and an async onSave; the content comes from the app as children.
Data states
ready
Permissions
edit
Events
onSave, onCancel
You can replace
classNames for each part; orientation and tone; title, description, saveLabel and successMessage; any Form fields or SettingsRow lines as children; useSettingsSection() lets your own controls read the read-only state

Guidelines

Use it when

  • A settings page made of several groups of related options, each with its own Save
  • Toggle lists where each switch saves at once (without onSave, with SettingsRow)
  • A danger zone with tone="danger"

Avoid it when

  • A single long form with one Save: use Form
  • A form in a dialog or sheet: use Dialog or Sheet with Form

Don't

  • Treating the permissions prop as protection: UI permission is not security, so the server must check again
  • Saving from inside the component: onSave is yours
  • Putting a Save button inside the children: the footer already has one
  • Hiding the reason when editing is not allowed: say why, so people know whom to ask

Design tokens

The semantic tokens this component uses. Change them once and every component follows; see Design tokens.

  • --rd-color-surface-default
  • --rd-color-surface-subtle
  • --rd-color-border-default
  • --rd-color-text-default
  • --rd-color-text-muted
  • --rd-color-feedback-danger
  • --rd-color-feedback-success
  • --rd-elevation-raised
  • --rd-radius-overlay