All Taste components
Onboarding
Clinic booking onboarding
A doctor booking app's welcome, with a calendar and heart badge in a tinted tile above the text.
tinted tile illustration · left-aligned text · 3-step dots · skip · next
Book a doctor in a few taps
See open slots at clinics near you and get a reminder before you go.
// Mobile-first screen for a React web app; the same markup maps to React Native via NativeWind (View, Text, Pressable, react-native-svg).
import { cn } from "@/lib/utils";
const slides = [
{ title: "Book a doctor in a few taps", body: "See open slots at clinics near you and get a reminder before you go." },
{ title: "Your records, together", body: "Prescriptions and reports stay in one safe place." },
{ title: "Talk to a doctor from home", body: "Video visits for the small things, any day of the week." },
];
function Illustration({ className }: { className?: string }) {
return (
<svg viewBox="0 0 240 210" aria-hidden="true" className={cn("h-full w-full", className)}>
<path d="M30 30v14M23 37h14" strokeWidth="4" strokeLinecap="round" strokeLinejoin="round" fill="none" className="stroke-brand-400" />
<rect x="44" y="46" width="144" height="128" rx="14" className="fill-neutral-50" />
<path d="M44 80V60a14 14 0 0 1 14-14h116a14 14 0 0 1 14 14v20z" className="fill-brand-600" />
<rect x="44" y="46" width="144" height="128" rx="14" strokeWidth="3" fill="none" className="stroke-brand-800" />
<rect x="78" y="34" width="9" height="24" rx="4.5" className="fill-brand-800" />
<rect x="146" y="34" width="9" height="24" rx="4.5" className="fill-brand-800" />
<rect x="60" y="96" width="18" height="14" rx="4" className="fill-brand-200" />
<rect x="90" y="96" width="18" height="14" rx="4" className="fill-brand-200" />
<rect x="120" y="96" width="18" height="14" rx="4" className="fill-brand-200" />
<rect x="150" y="96" width="18" height="14" rx="4" className="fill-brand-200" />
<rect x="60" y="120" width="18" height="14" rx="4" className="fill-brand-200" />
<rect x="90" y="120" width="18" height="14" rx="4" className="fill-brand-200" />
<rect x="120" y="120" width="18" height="14" rx="4" className="fill-brand-600" />
<rect x="150" y="120" width="18" height="14" rx="4" className="fill-brand-200" />
<rect x="60" y="144" width="18" height="14" rx="4" className="fill-brand-200" />
<rect x="90" y="144" width="18" height="14" rx="4" className="fill-brand-200" />
<circle cx="188" cy="164" r="30" strokeWidth="6" className="fill-brand-400 stroke-primary-soft" />
<path d="M188 177c-12-8-17-14-17-20a8.5 8.5 0 0 1 17-4 8.5 8.5 0 0 1 17 4c0 6-5 12-17 20z" className="fill-neutral-50" />
</svg>
);
}
function Dots({ step, total, className }: { step: number; total: number; className?: string }) {
return (
<div className={cn("flex gap-1.5", className)} role="img" aria-label={"Step " + (step + 1) + " of " + total}>
{Array.from({ length: total }, (_, i) => (
<span key={i} className={cn("h-1.5 rounded-full transition-all", i === step ? "w-[22px] bg-primary" : "w-1.5 bg-border-strong")} />
))}
</div>
);
}
export default function ClinicOnboarding({ step = 0, onNext, onSkip }: { step?: number; onNext?: () => void; onSkip?: () => void }) {
const slide = slides[step];
return (
<main className="mx-auto flex min-h-dvh max-w-md flex-col bg-bg px-6 pb-8 font-sans text-fg">
<header className="-mr-3.5 flex h-12 items-center justify-end">
<button type="button" onClick={onSkip} className="h-11 rounded px-3.5 text-sm font-medium text-fg-muted hover:bg-surface-2">
Skip
</button>
</header>
<div className="mb-7 grid aspect-square max-h-[42dvh] w-full place-items-center rounded-xl bg-primary-soft p-6">
<Illustration />
</div>
<h1 className="text-[26px] font-semibold leading-8 tracking-tight [text-wrap:balance]">{slide.title}</h1>
<p className="mt-2.5 text-[15px] leading-[22px] text-fg-muted">{slide.body}</p>
<Dots step={step} total={slides.length} className="mb-6 mt-auto pt-6" />
<button type="button" onClick={onNext} className="h-[52px] w-full rounded-lg bg-primary text-[15px] font-semibold text-primary-fg hover:bg-primary-hover">
{step === slides.length - 1 ? "Get started" : "Next"}
</button>
</main>
);
}
The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.