# Faq 9

A shadcn/ui block from the [@diarmuradi](https://diarmuradi.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/diarmuradi/faq-9).

- Page, with a live preview: https://shadcn.exchange/r/diarmuradi/faq-9
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/diarmuradi/faq-9-light-8ca60fef049e368d.png
- Registry item: https://diarmuradi.com/r/faq-9.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://diarmuradi.com/r/faq-9.json
```

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

## Dependencies

- npm packages: `lucide-react`
- Registry items: `https://diarmuradi.com/r/styles/base-nova/accordion.json`, `https://diarmuradi.com/r/styles/base-nova/toggle-group.json`

## Files

### `faq.tsx`

```tsx
"use client"

import { useState } from "react"

import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "@/components/ui/accordion"
import {
  ToggleGroup,
  ToggleGroupItem,
} from "@/components/ui/toggle-group"
import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react'

type FaqItem = {
  value: string
  question: string
  answer: string
}

type FaqCategoryValue = "General" | "Subscriptions" | "Services"

const faqsByCategory: Record<FaqCategoryValue, FaqItem[]> = {
  General: [
    {
      value: "item-1",
      question: "What services are included in the subscription?",
      answer:
        "Every plan includes unlimited design requests, a dedicated board, and two rounds of revision per task. Brand assets and source files are delivered with each request.",
    },
    {
      value: "item-2",
      question: "How many design requests can I make each month?",
      answer:
        "There is no request cap. Tasks are queued and worked one at a time so quality stays consistent. Pause or add requests whenever you need.",
    },
    {
      value: "item-3",
      question: "What is the turnaround time for design requests?",
      answer:
        "Smaller tasks such as graphics or copy tweaks take 2-4 hours. Larger pages and campaigns typically ship within one business day.",
    },
  ],
  Subscriptions: [
    {
      value: "item-4",
      question: "Can I pause my subscription?",
      answer:
        "Pause anytime from billing. Your queue is saved, and you can resume on the same plan without setup fees.",
    },
    {
      value: "item-5",
      question: "What if I need services outside the subscription?",
      answer:
        "One-off projects such as motion or 3D can be quoted separately. We will share a fixed price before any work starts.",
    },
  ],
  Services: [
    {
      value: "item-6",
      question: "Can I request revisions to the designs?",
      answer:
        "Yes. Each request includes two revision rounds. Extra rounds can be added as a follow-up task so nothing is blocked.",
    },
    {
      value: "item-7",
      question: "Who owns the final files?",
      answer:
        "You own everything we deliver. Source files, fonts we licensed for you, and exported assets are transferred at handoff.",
    },
  ],
}

const categories = Object.keys(faqsByCategory) as FaqCategoryValue[]

export function Faq() {
  const [activeCategory, setActiveCategory] =
    useState<FaqCategoryValue>("General")
  const faqs = faqsByCategory[activeCategory]

  return (
    <section
      aria-label="FAQ"
      className="mx-auto flex w-full max-w-2xl flex-col gap-8 text-foreground motion-reduce:**:animate-none motion-reduce:**:transition-none"
    >
      <header className="flex flex-col gap-3">
        <p className="flex items-center gap-2 text-sm text-muted-foreground">
          <span className="size-1.5 rounded-full bg-primary" />
          Subscriptions
        </p>
        <div className="flex flex-col gap-2">
          <h1 className="text-3xl font-semibold tracking-tight text-balance sm:text-4xl md:text-5xl">
            Plans, seats, and renewals
          </h1>
          <p className="text-muted-foreground">
            Use the rail to switch topics. Each question opens in place.
          </p>
        </div>
      </header>

      <div className="grid gap-8 md:grid-cols-[10rem_1fr]">
        <ToggleGroup
          value={[activeCategory]}
          onValueChange={(value) => {
            const category = categories.find(
              (category) => category === value[0]
            )
            if (category) setActiveCategory(category)
          }}
          orientation="vertical"
          spacing={1}
          className="flex-row md:flex-col"
        >
          {categories.map((category) => (
            <ToggleGroupItem
              key={category}
              value={category}
              className="justify-start rounded-lg px-3 py-2 text-sm"
            >
              {category}
            </ToggleGroupItem>
          ))}
        </ToggleGroup>

        <h2 className="sr-only">{activeCategory} questions</h2>

        <Accordion
          key={activeCategory}
          defaultValue={faqs.slice(0, 1).map((item) => item.value)}
          className="gap-2"
        >
          {faqs.map((item) => (
            <AccordionItem
              key={item.value}
              value={item.value}
              className="overflow-hidden rounded-xl border-0 bg-muted"
            >
              <AccordionTrigger className="p-4 text-left hover:no-underline *:data-[slot=accordion-trigger-icon]:hidden">
                <span className="font-medium">{item.question}</span>
                <span className="ml-auto flex size-7 shrink-0 items-center justify-center">
                  <ChevronDownIcon  aria-hidden="true" className="size-3.5 text-muted-foreground group-aria-expanded/accordion-trigger:hidden" />
                  <ChevronUpIcon  aria-hidden="true" className="hidden size-3.5 text-muted-foreground group-aria-expanded/accordion-trigger:inline" />
                </span>
              </AccordionTrigger>
              <AccordionContent className="px-4 pb-4 text-sm text-muted-foreground">
                {item.answer}
              </AccordionContent>
            </AccordionItem>
          ))}
        </Accordion>
      </div>
    </section>
  )
}
```
