shadcn.io is an independent project built on shadcn/ui
Language starts on English and theme on System. Email and security alerts start on, marketing starts off, and two-factor starts off. Each switch sits on a bordered row.
Use it for an account preferences page. One on or off setting can be a lone Switch. In React, Base UI does not remember the defaults. The form's initial values do.
Installation
Usage
<form className="w-full max-w-2xl" onSubmit={form.handleSubmit(onSubmit)}>
<FieldGroup className="gap-8">
<div className="flex flex-col gap-1">
<h3 className="font-medium text-lg">Preferences</h3>
<p className="text-muted-foreground text-sm">
Manage your application preferences
</p>
</div>
<FieldGroup className="gap-4">
<Controller
control={form.control}
name="language"
render={({ field }) => (
<Field>
<FieldLabel htmlFor="settings-form-language">
Language
</FieldLabel>
<Select
items={languages}
name={field.name}
onValueChange={(next) => field.onChange(next ?? "")}
value={field.value || null}
>
<SelectTrigger className="w-full" id="settings-form-language">
<SelectValue />
</SelectTrigger>
<SelectContent>
{languages.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
{/* The rest of the file is under Installation. */}FAQ
What is selected when the form opens?
defaultValues sets the language to en, the theme to system, email notifications and security alerts on, and marketing emails and two-factor authentication off.
How do language and theme write back to the form?
Each is a Controller with a Select and a FieldDescription: "Choose your preferred language." and "Select your preferred theme." Select takes items, value={field.value || null}, and onValueChange stores the next value.
How is each switch connected?
The three notification rows come from one notifications array mapped to a Controller each; Two-Factor Authentication has its own. Switch takes checked and onCheckedChange={field.onChange}.
What does the schema actually reject?
Almost nothing: language and theme are z.string() and the four switches z.boolean(), and every control always holds a valid value, so there are no FieldErrors. Narrow the selects with z.enum if the server needs it.
API Reference
Field
Sets htmlFor="settings-form-language", htmlFor="settings-form-theme", orientation="horizontal", htmlFor, settings-form- and notification. The rest is on the Field page.
Select
Sets items={languages}, name={field.name}, onValueChange, next, id="settings-form-language" and value={item.value}. The rest is on the Select page.
Switch
Sets checked={field.value}, id, settings-form-, notification, name and name={field.name}. The rest is on the Switch page.
Button
Sets type="submit". The rest is on the Button page.





