All Taste components
App screens
Workspace settings
A settings page with its own section menu, labelled form rows, switches and a save bar.
icon rail · section nav · logo upload · inputs · prefixed URL · selects · switches
Settings
Manage your workspace, team and billing.
"use client";
import { useState } from "react";
import { Bell, Check, CreditCard, Lock, Plug, Settings, Users } from "lucide-react";
import { cn } from "@/lib/utils";
const sections = [
{ group: "Workspace", items: [
{ label: "General", icon: Settings, current: true },
{ label: "Members", icon: Users, count: 8 },
{ label: "Billing", icon: CreditCard },
{ label: "Integrations", icon: Plug },
] },
{ group: "Account", items: [
{ label: "Notifications", icon: Bell },
{ label: "Security", icon: Lock },
] },
];
const reminderDefaults = [
{ id: "before", label: "Remind 3 days before the due date", on: true },
{ id: "overdue", label: "Remind every 7 days when overdue", on: true },
{ id: "receipt", label: "Send a receipt when paid", on: false },
];
const input = "h-9 w-full rounded border border-border-strong bg-bg px-3 text-sm text-fg outline-none focus:border-primary focus:ring-[3px] focus:ring-primary/20";
function Row({ title, help, children }: { title: string; help: string; children: React.ReactNode }) {
return (
<div className="grid gap-3 border-b border-border py-5 md:grid-cols-[200px_minmax(0,1fr)] md:gap-6">
<div><h3 className="text-[13px] font-medium">{title}</h3><p className="text-xs text-fg-subtle">{help}</p></div>
<div>{children}</div>
</div>
);
}
export default function SettingsPage() {
const [reminders, setReminders] = useState(reminderDefaults);
return (
<main className="mx-auto max-w-5xl bg-bg px-4 py-8 font-sans text-sm text-fg sm:px-8">
<header className="border-b border-border pb-4">
<h1 className="text-2xl font-medium tracking-tight">Settings</h1>
<p className="text-fg-muted">Manage your workspace, team and billing.</p>
</header>
<div className="mt-6 grid gap-8 md:grid-cols-[200px_minmax(0,1fr)]">
<nav aria-label="Settings" className="flex gap-1 overflow-x-auto md:grid md:content-start">
{sections.map((s) => (
<div key={s.group} className="contents md:grid md:gap-0.5">
<p className="hidden px-2 pb-1 pt-3 text-[11px] font-medium text-fg-subtle first:pt-0 md:block">{s.group}</p>
{s.items.map(({ label, icon: Icon, current, count }) => (
<a key={label} href="#" aria-current={current ? "page" : undefined}
className={cn("flex h-8 shrink-0 items-center gap-2.5 rounded px-2 font-medium text-fg-muted hover:bg-surface-2 hover:text-fg",
current && "bg-surface-2 text-fg")}>
<Icon className="size-4" aria-hidden />{label}
{count && <span className="ml-auto text-xs text-fg-subtle">{count}</span>}
</a>
))}
</div>
))}
</nav>
<form aria-label="General settings" onSubmit={(e) => e.preventDefault()}>
<Row title="Logo" help="Shown on invoices and emails.">
<div className="flex flex-wrap items-center gap-3">
<span className="grid size-11 place-items-center rounded-lg bg-primary text-lg font-semibold text-primary-fg">K</span>
<button type="button" className="h-8 rounded border border-border-strong px-3 text-[13px] font-medium hover:bg-surface">Replace</button>
<button type="button" className="h-8 rounded px-3 text-[13px] font-medium hover:bg-surface-2">Remove</button>
<span className="text-xs text-fg-subtle">SVG or PNG, 512 px</span>
</div>
</Row>
<Row title="Workspace" help="Your legal business details.">
<div className="grid gap-3 sm:grid-cols-2">
<label className="grid gap-1"><span className="text-xs font-medium">Business name</span><input className={input} defaultValue="Kaveri Foods Pvt Ltd" /></label>
<label className="grid gap-1"><span className="text-xs font-medium">GSTIN</span><input className={input} defaultValue="29AAGCK4127M1Z5" /></label>
<label className="grid gap-1 sm:col-span-2"><span className="text-xs font-medium">Workspace URL</span>
<span className="flex h-9 overflow-hidden rounded border border-border-strong focus-within:border-primary focus-within:ring-[3px] focus-within:ring-primary/20">
<span className="flex items-center border-r border-border bg-surface px-3 text-[13px] text-fg-muted">app.ledgerline.in/</span>
<input className="min-w-0 flex-1 bg-bg px-3 outline-none" defaultValue="kaveri-foods" />
</span>
</label>
</div>
</Row>
<Row title="Region" help="Used for dates, tax and currency.">
<div className="grid gap-3 sm:grid-cols-2">
<select aria-label="Time zone" className={input} defaultValue="Asia/Kolkata"><option value="Asia/Kolkata">(GMT+5:30) Kolkata</option></select>
<select aria-label="Currency" className={input} defaultValue="INR"><option value="INR">Indian rupee (₹)</option></select>
</div>
</Row>
<Row title="Reminders" help="Sent to customers for you.">
<ul className="grid gap-1">
{reminders.map((r) => (
<li key={r.id} className="flex items-center justify-between gap-4 py-1.5">
<span>{r.label}</span>
<button type="button" role="switch" aria-checked={r.on} aria-label={r.label}
onClick={() => setReminders((all) => all.map((x) => (x.id === r.id ? { ...x, on: !x.on } : x)))}
className="relative h-5 w-9 shrink-0 rounded-full bg-border-strong transition-colors aria-checked:bg-primary">
<span className={cn("absolute top-0.5 size-4 rounded-full bg-bg shadow-sm transition-[left]", r.on ? "left-[18px]" : "left-0.5")} />
</button>
</li>
))}
</ul>
</Row>
<div className="flex flex-wrap items-center justify-end gap-2 pt-5">
<p className="mr-auto text-xs text-fg-subtle">Last saved 2 days ago by Asha Rao</p>
<button type="button" className="h-9 rounded px-3 font-medium hover:bg-surface-2">Cancel</button>
<button type="submit" className="inline-flex h-9 items-center gap-1.5 rounded bg-primary px-3.5 font-medium text-primary-fg hover:bg-primary-hover">
<Check className="size-4" aria-hidden /> Save changes
</button>
</div>
</form>
</div>
</main>
);
}
The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.