Skip to content
All Taste components

Features

Features — accordion with visual

A numbered accordion of features on the left; opening one changes the picture on the right.

4 numbered items · one open at a time · picture follows the open item · picture first on small screens

For studios with regulars

Everything between “can I book?” and “see you Thursday”

01Online booking page

Clients pick a service and a free time, day or night. You set the hours and the gaps between appointments.

Learn more
02Deposits and payments

Take a deposit when they book and the rest after. Card, UPI or cash — all in one list.

Learn more
03Reminders by WhatsApp and email

A message the day before with a one-tap reschedule link. Fewer no-shows, fewer phone calls.

Learn more
04Client notes

Remember the colour formula, the allergy and the favourite playlist. Notes stay with the client.

Learn more
"use client";
import { useState, type ReactNode } from "react";
import { ArrowRight, ChevronDown } from "lucide-react";
import { cn } from "@/lib/utils";

type Item = { title: string; text: string; href: string; picture: ReactNode };

/* Replace these with screenshots of your product, or keep the drawn cards. */
const card = "w-full max-w-[340px] rounded-lg border border-border bg-bg p-4 text-[12.5px] text-fg shadow-xl";
const items: Item[] = [
  { title: "Online booking page", href: "/booking", text: "Clients pick a service and a free time, day or night. You set the hours and the gaps between appointments.",
    picture: <div className={card}><p className="mb-3 font-semibold">Pick a time · Thu 16 Oct</p><div className="grid grid-cols-4 gap-1.5 text-center">{["9:00", "9:45", "10:30", "11:15", "12:00", "14:00", "14:45", "15:30"].map((t, i) => <span key={t} className={cn("rounded-sm border border-border py-1.5 tabular-nums text-fg-muted", i === 2 && "border-primary bg-primary text-primary-fg")}>{t}</span>)}</div></div> },
  { title: "Deposits and payments", href: "/payments", text: "Take a deposit when they book and the rest after. Card, UPI or cash — all in one list.",
    picture: <div className={card + " grid gap-2"}>{[["Deposit · Anaya S.", "₹500"], ["Paid in full · Dev M.", "₹350"], ["Due at visit · Meera I.", "₹800"]].map(([a, b]) => <div key={a} className="flex justify-between rounded border border-border px-3 py-2.5"><span>{a}</span><span className="font-medium tabular-nums">{b}</span></div>)}</div> },
  { title: "Reminders by WhatsApp and email", href: "/reminders", text: "A message the day before with a one-tap reschedule link. Fewer no-shows, fewer phone calls.",
    picture: <div className={card + " grid gap-2.5"}><p className="text-fg-subtle">Tomorrow, 9:00 am</p><p className="rounded-lg border border-border px-3 py-2">Hi Anaya! See you tomorrow at 10:30 for Colour. Need to move it? Tap here.</p></div> },
  { title: "Client notes", href: "/clients", text: "Remember the colour formula, the allergy and the favourite playlist. Notes stay with the client.",
    picture: <div className={card + " grid gap-2"}><p className="font-semibold">Anaya Shah</p><p className="rounded border border-border px-3 py-2.5">Formula: 7.1 + 20 vol</p><p className="rounded border border-border px-3 py-2.5">Allergic to lavender oil</p></div> },
];

export function FeaturesAccordion() {
  const [open, setOpen] = useState(0);
  return (
    <section aria-labelledby="features-title" className="bg-surface font-sans">
      <div className="mx-auto max-w-6xl px-4 py-16 sm:px-6 lg:py-24">
        <p className="text-[13px] font-medium text-primary">For studios with regulars</p>
        <h2 id="features-title" className="mt-3.5 max-w-2xl text-balance text-3xl font-semibold tracking-tight text-fg sm:text-4xl">
          Everything between “can I book?” and “see you Thursday”
        </h2>

        <div className="mt-12 grid items-center gap-7 lg:grid-cols-[1fr_1.15fr] lg:gap-14">
          <div className="border-t border-border">
            {items.map((item, i) => {
              const isOpen = open === i;
              return (
                <div key={item.title} className="border-b border-border">
                  <h3>
                    <button
                      type="button"
                      aria-expanded={isOpen}
                      onClick={() => setOpen(i)}
                      className={cn("flex w-full items-center gap-3.5 py-[18px] text-left text-base font-semibold tracking-tight transition", isOpen ? "text-fg" : "text-fg-muted hover:text-fg")}
                    >
                      <span className={cn("text-xs font-medium tabular-nums", isOpen ? "text-primary" : "text-fg-subtle")}>{String(i + 1).padStart(2, "0")}</span>
                      {item.title}
                      <ChevronDown className={cn("ml-auto size-4 text-fg-subtle transition-transform", isOpen && "rotate-180")} aria-hidden />
                    </button>
                  </h3>
                  {isOpen && (
                    <div className="grid gap-3 pb-5 pl-[34px]">
                      <p className="text-pretty text-[14.5px] leading-relaxed text-fg-muted">{item.text}</p>
                      <a href={item.href} className="inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline">Learn more <ArrowRight className="size-4" aria-hidden /></a>
                    </div>
                  )}
                </div>
              );
            })}
          </div>
          <div aria-hidden className="-order-1 grid place-items-center rounded-xl bg-surface bg-gradient-to-br from-primary-soft to-bg p-5 sm:p-8 lg:order-none lg:min-h-[320px]">
            {items[open].picture}
          </div>
        </div>
      </div>
    </section>
  );
}

The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.