# Card Accordion With Icons

A shadcn/ui block from the [@weinc](https://we.inc/components?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/weinc/card-accordion-with-icons).

- Page, with a live preview: https://shadcn.exchange/r/weinc/card-accordion-with-icons
- Screenshot: https://shadcn.exchange/shot/weinc/card-accordion-with-icons/light.png
- Registry item: https://we.inc/r/card-accordion-with-icons.json
- Listed: 2026-10-29, source last changed 2026-10-29

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/weinc/card-accordion-with-icons.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Files

### `components/we-inc/card-accordion-with-icons.tsx`

```tsx
import { useState } from "react";

const services = [
  { title: "Check-up and clean", price: "From $95", tone: "bg-teal-100 text-teal-800", icon: "M12 3c-3 0-5 1.5-5 4.5 0 2 .8 3 1 5.5.3 3 .7 7 2 7s1.2-4 2-4 .7 4 2 4 1.7-4 2-7c.2-2.5 1-3.5 1-5.5C17 4.5 15 3 12 3z", body: "A full examination, scale and polish with our hygienist, plus X-rays once every two years. Plan for forty minutes in the chair." },
  { title: "Whitening", price: "From $340", tone: "bg-amber-100 text-amber-800", icon: "M12 3v3M12 18v3M3 12h3M18 12h3M5.6 5.6l2.1 2.1M16.3 16.3l2.1 2.1M5.6 18.4l2.1-2.1M16.3 7.7l2.1-2.1M12 8a4 4 0 100 8 4 4 0 000-8z", body: "Custom trays made from a scan of your teeth and two weeks of gel to use at home. Most people see four to six shades lighter." },
  { title: "Emergency appointments", price: "Same day", tone: "bg-rose-100 text-rose-800", icon: "M12 3a9 9 0 100 18 9 9 0 000-18zM12 7v5l3 2", body: "Call before 10am and we will see you the same day for pain, swelling or a broken tooth. Evening slots are kept free on weekdays." },
  { title: "Children's dentistry", price: "Free under 12", tone: "bg-sky-100 text-sky-800", icon: "M8 10a2 2 0 100-4 2 2 0 000 4zM16 10a2 2 0 100-4 2 2 0 000 4zM7 15c1.3 1.6 3 2.5 5 2.5s3.7-.9 5-2.5", body: "Short, gentle visits with a dentist who sees children every day. Fissure sealants and fluoride varnish are included." },
];

export default function CardAccordionWithIcons() {
  const [open, setOpen] = useState(0);
  return (
    <section className="cia bg-[#f6f1ea] px-5 py-16 sm:py-20">
      <style>{`
        .cia-panel { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .3s cubic-bezier(.2,.7,.2,1); }
        .cia-panel[data-open] { grid-template-rows: 1fr; }
        @media (prefers-reduced-motion: reduce) { .cia-panel { transition: none; } }
      `}</style>
      <div className="mx-auto max-w-2xl">
        <h2 className="text-center text-2xl font-semibold tracking-tight text-stone-900 sm:text-3xl">Treatments at Brightwater Dental</h2>
        <p className="mt-2 text-center text-[15px] text-stone-600">Tap a treatment to see what is included.</p>
        <ul className="mt-10 space-y-3">
          {services.map((s, i) => {
            const isOpen = open === i;
            return (
              <li key={s.title} className={`rounded-2xl bg-white transition-shadow ${isOpen ? "shadow-md shadow-stone-300/50" : "shadow-sm shadow-stone-200"}`}>
                <h3>
                  <button
                    type="button"
                    id={`cia-b${i}`}
                    aria-expanded={isOpen}
                    aria-controls={`cia-p${i}`}
                    onClick={() => setOpen(isOpen ? -1 : i)}
                    className="flex min-h-[72px] w-full items-center gap-4 rounded-2xl p-4 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-stone-800"
                  >
                    <span className={`grid h-11 w-11 shrink-0 place-items-center rounded-xl ${s.tone}`}>
                      <svg viewBox="0 0 24 24" className="h-6 w-6" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d={s.icon} /></svg>
                    </span>
                    <span className="flex-1 text-base font-semibold text-stone-900">{s.title}</span>
                    <span className="hidden text-sm text-stone-600 sm:inline">{s.price}</span>
                    <svg viewBox="0 0 20 20" className={`h-5 w-5 shrink-0 text-stone-500 transition-transform duration-300 motion-reduce:transition-none ${isOpen ? "rotate-180" : ""}`} fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true"><path d="M5 7.5l5 5 5-5" strokeLinecap="round" strokeLinejoin="round" /></svg>
                  </button>
                </h3>
                <div id={`cia-p${i}`} role="region" aria-labelledby={`cia-b${i}`} data-open={isOpen ? "" : undefined} className="cia-panel">
                  <div className="overflow-hidden" {...(isOpen ? {} : { inert: "" })}>
                    <div className="px-4 pb-5 sm:pl-[76px]">
                      <p className="text-[15px] leading-relaxed text-stone-700">{s.body}</p>
                      <p className="mt-3 text-sm font-medium text-stone-900 sm:hidden">{s.price}</p>
                      <a href="#" className="mt-4 inline-flex h-10 items-center rounded-full bg-stone-900 px-4 text-sm font-medium text-white hover:bg-stone-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-stone-900 focus-visible:ring-offset-2">Book this</a>
                    </div>
                  </div>
                </div>
              </li>
            );
          })}
        </ul>
      </div>
    </section>
  );
}
```
