An app's Settings window: a tabs switches between General, Appearance and Notifications, each a grouped form of switches, pop-up buttons and a slider.
registry/macos/blocks/preferences-01/preferences-01.tsx
"use client"
import * as React from "react"
import { cn } from "@/lib/utils"
import {
GroupedForm,
GroupedFormGroup,
GroupedFormRow,
GroupedFormRowControl,
GroupedFormRowDescription,
GroupedFormRowLabel,
GroupedFormRowTitle,
GroupedFormSection,
} from "@/registry/macos/ui/grouped-form"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/registry/macos/ui/select"
import { Slider } from "@/registry/macos/ui/slider"
import { Switch } from "@/registry/macos/ui/switch"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/registry/macos/ui/tabs"
import {
Window,
WindowContent,
WindowControls,
WindowMain,
WindowTitle,
WindowTitlebar,
} from "@/registry/macos/ui/window"
// A pop-up button in a settings row.
function Choice({ label, items, defaultValue }: { label: string; items: Record<string, string>; defaultValue: string }) {
return (
<Select defaultValue={defaultValue} items={items}>
<SelectTrigger variant="borderless" aria-label={label}>
<SelectValue />
</SelectTrigger>
<SelectContent>
{Object.entries(items).map(([value, text]) => (
<SelectItem key={value} value={value}>
{text}
</SelectItem>
))}
</SelectContent>
</Select>
)
}
// A settings row with a title, an optional description and a control.
function Row({ title, description, children }: { title: string; description?: string; children: React.ReactNode }) {
return (
<GroupedFormRow className={cn(description && "items-start")}>
{description ? (
<GroupedFormRowLabel>
<GroupedFormRowTitle>{title}</GroupedFormRowTitle>
<GroupedFormRowDescription>{description}</GroupedFormRowDescription>
</GroupedFormRowLabel>
) : (
<GroupedFormRowTitle>{title}</GroupedFormRowTitle>
)}
<GroupedFormRowControl>{children}</GroupedFormRowControl>
</GroupedFormRow>
)
}
// An app's Settings window: a tabs picks General, Appearance
// or Notifications, each a grouped form of switches, pop-up buttons and a
// slider. Replace the rows with your own settings.
export function Preferences01({ className, ...props }: React.ComponentProps<typeof Window>) {
return (
<Window className={cn("h-[460px] w-[560px]", className)} {...props}>
<WindowMain>
<WindowTitlebar>
<WindowControls />
<WindowTitle>Settings</WindowTitle>
</WindowTitlebar>
<WindowContent className="flex flex-col">
<Tabs defaultValue="general" className="flex min-h-0 flex-1 flex-col items-center gap-4 pt-3">
<TabsList>
<TabsTrigger value="general">General</TabsTrigger>
<TabsTrigger value="appearance">Appearance</TabsTrigger>
<TabsTrigger value="notifications">Notifications</TabsTrigger>
</TabsList>
<TabsContent value="general" className="w-full px-5 pb-5">
<GroupedForm>
<GroupedFormSection>
<GroupedFormGroup>
<Row title="Open at login">
<Switch size="mini" aria-label="Open at login" />
</Row>
<Row title="Check for updates automatically">
<Switch size="mini" defaultChecked aria-label="Check for updates automatically" />
</Row>
</GroupedFormGroup>
</GroupedFormSection>
<GroupedFormSection>
<GroupedFormGroup>
<Row title="New documents open in">
<Choice label="New documents open in" defaultValue="documents" items={{ documents: "Documents", desktop: "Desktop", icloud: "iCloud Drive" }} />
</Row>
<Row title="Language">
<Choice label="Language" defaultValue="system" items={{ system: "System Language", en: "English", de: "Deutsch", fr: "Français" }} />
</Row>
</GroupedFormGroup>
</GroupedFormSection>
</GroupedForm>
</TabsContent>
<TabsContent value="appearance" className="w-full px-5 pb-5">
<GroupedForm>
<GroupedFormSection>
<GroupedFormGroup>
<Row title="Appearance">
<Choice label="Appearance" defaultValue="auto" items={{ auto: "Auto", light: "Light", dark: "Dark" }} />
</Row>
<Row title="Text size">
<div className="w-40">
<Slider defaultValue={[40]} aria-label="Text size" />
</div>
</Row>
<Row title="Show the sidebar" description="Hide it to make more room for what you’re working on.">
<Switch size="mini" defaultChecked aria-label="Show the sidebar" />
</Row>
</GroupedFormGroup>
</GroupedFormSection>
</GroupedForm>
</TabsContent>
<TabsContent value="notifications" className="w-full px-5 pb-5">
<GroupedForm>
<GroupedFormSection>
<GroupedFormGroup>
<Row title="Allow notifications">
<Switch size="mini" defaultChecked aria-label="Allow notifications" />
</Row>
<Row title="Sound">
<Choice label="Sound" defaultValue="glass" items={{ none: "None", glass: "Glass", ping: "Ping", pop: "Pop" }} />
</Row>
<Row title="Badge the app icon">
<Switch size="mini" defaultChecked aria-label="Badge the app icon" />
</Row>
<Row title="Show previews">
<Choice label="Show previews" defaultValue="always" items={{ always: "Always", never: "Never" }} />
</Row>
</GroupedFormGroup>
</GroupedFormSection>
</GroupedForm>
</TabsContent>
</Tabs>
</WindowContent>
</WindowMain>
</Window>
)
}