Skip to content
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.

Logo

Shown on invoices and emails.

KSVG or PNG, 512 px

Workspace

Your legal business details.

Region

Used for dates, tax and currency.

Reminders

Sent to customers for you.

Remind 3 days before the due date
Remind every 7 days when overdue
Send a receipt when paid
Last saved 2 days ago by Asha Rao
"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.