# FAQ Accordion With Plus Minus Icon

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/faq-accordion-with-plus-minus-icon).

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

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/weinc/faq-accordion-with-plus-minus-icon.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/faq-accordion-with-plus-minus-icon.tsx`

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

const faqs = [
  { q: "Can I bring a guest for the day?", a: "Members on the Resident plan can sign in two guests a day at the front desk. Guests get Wi-Fi, coffee and a hot desk, but not the phone booths." },
  { q: "Are the desks available at night?", a: "Fixed desks are open around the clock with your key fob. Hot desks and the kitchen close at 10pm so the cleaners can get in." },
  { q: "How does billing work if I pause?", a: "You can pause once a year for up to two months. We hold your locker and stop charging from the first of the next month." },
  { q: "Is there parking for bikes?", a: "There is a covered, locked bike room in the basement with forty stands, a pump and a shower next door." },
  { q: "Can I use the address for my company?", a: "Yes. Any paid plan includes a registered business address and post handling, with a photo of each letter sent the day it arrives." },
];

export default function FaqAccordionWithPlusMinusIcon() {
  const [open, setOpen] = useState<Set<number>>(() => new Set([0]));
  const toggle = (i: number) =>
    setOpen((prev) => {
      const next = new Set(prev);
      if (next.has(i)) next.delete(i);
      else next.add(i);
      return next;
    });
  return (
    <section className="fpm bg-slate-950 px-5 py-16 text-white sm:py-24">
      <style>{`
        .fpm-panel { display: grid; grid-template-rows: 0fr; opacity: 0; transition: grid-template-rows .3s ease, opacity .3s ease; }
        .fpm-panel[data-open] { grid-template-rows: 1fr; opacity: 1; }
        .fpm-v { transition: transform .3s cubic-bezier(.2,.7,.2,1); transform-origin: center; }
        [aria-expanded="true"] .fpm-v { transform: rotate(90deg); }
        @media (prefers-reduced-motion: reduce) { .fpm-panel, .fpm-v { transition: none; } }
      `}</style>
      <div className="mx-auto grid max-w-5xl gap-10 md:grid-cols-[1fr_1.6fr] md:gap-16">
        <div>
          <p className="text-sm font-medium text-sky-300">Ropewalk Studios</p>
          <h2 className="mt-2 text-3xl font-semibold tracking-tight">Questions before you join</h2>
          <p className="mt-4 text-[15px] leading-relaxed text-slate-400">Something else on your mind? Ask at the front desk or reply to your welcome email.</p>
        </div>
        <ul className="border-t border-white/10">
          {faqs.map((f, i) => {
            const isOpen = open.has(i);
            return (
              <li key={f.q} className="border-b border-white/10">
                <h3>
                  <button
                    type="button"
                    id={`fpm-b${i}`}
                    aria-expanded={isOpen}
                    aria-controls={`fpm-p${i}`}
                    onClick={() => toggle(i)}
                    className="flex min-h-[60px] w-full items-center justify-between gap-6 py-5 text-left text-[17px] font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-300 focus-visible:ring-offset-4 focus-visible:ring-offset-slate-950"
                  >
                    {f.q}
                    <span className={`grid h-8 w-8 shrink-0 place-items-center rounded-full border transition-colors ${isOpen ? "border-sky-300 bg-sky-300 text-slate-950" : "border-white/25 text-white"}`}>
                      <svg viewBox="0 0 16 16" className="h-3.5 w-3.5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden="true">
                        <path d="M2 8h12" />
                        <path className="fpm-v" d="M8 2v12" />
                      </svg>
                    </span>
                  </button>
                </h3>
                <div id={`fpm-p${i}`} role="region" aria-labelledby={`fpm-b${i}`} data-open={isOpen ? "" : undefined} className="fpm-panel">
                  <div className="overflow-hidden" {...(isOpen ? {} : { inert: "" })}>
                    <p className="pb-6 pr-12 text-[15px] leading-relaxed text-slate-300">{f.a}</p>
                  </div>
                </div>
              </li>
            );
          })}
        </ul>
      </div>
    </section>
  );
}
```
