All Taste components
Mobile screens
Profile & settings
An account screen with the person's details and grouped settings rows, some with switches.
profile card · inset grouped rows · 3 switches · value + chevron rows · log out · tab bar
Profile
PM
Priya Menon
+91 98450 12321
priya.menon@mailbox.in
Preferences
Push notifications
Reminders by SMS
Dark appearance
LanguageEnglish
Account
Saved addresses3
Payment methods2
Privacy & security
// Mobile-first page; the same markup maps to React Native via NativeWind (SectionList/Switch).
"use client";
import { useState } from "react";
import { Bell, CalendarDays, ChevronRight, CreditCard, Globe, Heart, Home, LogOut, MapPin, MessageCircle, Moon, Pencil, ShieldCheck, User } from "lucide-react";
import { cn } from "@/lib/utils";
const me = { name: "Priya Menon", phone: "+91 98450 12321", email: "priya.menon@mailbox.in", initials: "PM" };
const toggles = [
{ id: "push", label: "Push notifications", icon: Bell, tone: "bg-primary text-primary-fg", on: true },
{ id: "sms", label: "Reminders by SMS", icon: MessageCircle, tone: "bg-success text-bg", on: true },
{ id: "dark", label: "Dark appearance", icon: Moon, tone: "bg-info text-bg", on: false },
];
const links = {
Preferences: [{ label: "Language", icon: Globe, tone: "bg-warning text-bg", value: "English", href: "/settings/language" }],
Account: [
{ label: "Saved addresses", icon: MapPin, tone: "bg-primary text-primary-fg", value: "3", href: "/settings/addresses" },
{ label: "Payment methods", icon: CreditCard, tone: "bg-success text-bg", value: "2", href: "/settings/payments" },
{ label: "Privacy & security", icon: ShieldCheck, tone: "bg-info text-bg", value: "", href: "/settings/privacy" },
],
};
const tabs = [
{ label: "Home", icon: Home },
{ label: "Bookings", icon: CalendarDays },
{ label: "Saved", icon: Heart },
{ label: "Profile", icon: User, current: true },
];
function Row({ icon: Icon, tone, label, divided, children }:
{ icon: typeof Bell; tone: string; label: string; divided?: boolean; children: React.ReactNode }) {
return (
<div className="flex items-center gap-3 pl-3">
<span className={cn("grid size-[30px] shrink-0 place-items-center rounded-sm", tone)}><Icon className="size-4" aria-hidden /></span>
<div className={cn("flex min-h-12 flex-1 items-center gap-2 pr-3 text-[14.5px]", divided && "border-t border-border")}>
<span className="min-w-0 flex-1">{label}</span>
{children}
</div>
</div>
);
}
export default function ProfileScreen() {
const [on, setOn] = useState<Record<string, boolean>>(Object.fromEntries(toggles.map((t) => [t.id, t.on])));
return (
<div className="mx-auto flex min-h-dvh max-w-md flex-col bg-bg font-sans text-fg">
<main className="flex-1 px-4 pb-6 pt-2">
<h1 className="text-2xl font-semibold tracking-tight">Profile</h1>
<div className="mt-3 flex items-center gap-3 rounded-lg bg-surface p-3">
<span className="grid size-[52px] place-items-center rounded-full bg-primary-soft text-[17px] font-medium text-primary-soft-fg">{me.initials}</span>
<div className="min-w-0 flex-1">
<p className="text-[15px] font-semibold">{me.name}</p>
<p className="text-xs tabular-nums text-fg-muted">{me.phone}</p>
<p className="truncate text-xs text-fg-muted">{me.email}</p>
</div>
<a href="/profile/edit" aria-label="Edit profile" className="-mr-2 grid size-11 place-items-center rounded-full hover:bg-surface-2"><Pencil className="size-5" /></a>
</div>
<h2 className="mx-1 mb-1.5 mt-5 text-xs font-medium text-fg-muted">Preferences</h2>
<div className="overflow-hidden rounded-lg bg-surface">
{toggles.map((t, i) => (
<Row key={t.id} icon={t.icon} tone={t.tone} label={t.label} divided={i > 0}>
<button
type="button"
role="switch"
aria-checked={on[t.id]}
aria-label={t.label}
onClick={() => setOn((s) => ({ ...s, [t.id]: !s[t.id] }))}
className="relative h-[22px] w-[38px] shrink-0 rounded-full bg-border-strong transition-colors aria-checked:bg-primary"
>
<span className={cn("absolute top-[3px] size-4 rounded-full bg-bg shadow-sm transition-[left]", on[t.id] ? "left-[19px]" : "left-[3px]")} />
</button>
</Row>
))}
{links.Preferences.map((l) => (
<Row key={l.label} icon={l.icon} tone={l.tone} label={l.label} divided>
<a href={l.href} aria-label={l.label + ": " + l.value} className="flex min-h-11 items-center gap-0.5 text-[13.5px] text-fg-subtle">{l.value}<ChevronRight className="size-4" /></a>
</Row>
))}
</div>
<h2 className="mx-1 mb-1.5 mt-5 text-xs font-medium text-fg-muted">Account</h2>
<div className="overflow-hidden rounded-lg bg-surface">
{links.Account.map((l, i) => (
<Row key={l.label} icon={l.icon} tone={l.tone} label={l.label} divided={i > 0}>
<a href={l.href} aria-label={l.label} className="flex min-h-11 items-center gap-0.5 text-[13.5px] tabular-nums text-fg-subtle">{l.value}<ChevronRight className="size-4" /></a>
</Row>
))}
</div>
<button type="button" className="mt-4 flex h-12 w-full items-center justify-center gap-2 rounded-lg bg-surface text-[14.5px] font-medium text-danger">
<LogOut className="size-[18px]" aria-hidden /> Log out
</button>
</main>
<nav aria-label="Main" className="sticky bottom-0 grid grid-cols-4 border-t border-border bg-bg px-1.5 pb-[max(env(safe-area-inset-bottom),8px)] pt-1">
{tabs.map(({ label, icon: Icon, current }) => (
<a key={label} href="#" aria-current={current ? "page" : undefined}
className={cn("flex min-h-11 flex-col items-center justify-center gap-0.5 text-[10.5px] font-medium", current ? "text-primary" : "text-fg-subtle")}>
<Icon className="size-[22px]" aria-hidden />{label}
</a>
))}
</nav>
</div>
);
}
The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.