FAQ

FAQ 01 — Accordion

Centered accordion FAQ in a card with seven default questions and a contact link below.

$ npx shadcn@latest add @ludusvibe/faq-01
Open in v0

Code

Installed to components/sections/faq-01.tsx — it's yours to edit.

"use client"

import * as React from "react"
import { ArrowRight } from "lucide-react"

import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "@/components/ui/accordion"
import { Reveal } from "@/components/ludus/reveal"
import { cn } from "@/lib/utils"

export type Faq01Item = {
  question: string
  answer: React.ReactNode
}

export type Faq01Props = {
  eyebrow?: string
  title?: React.ReactNode
  description?: string
  items?: Faq01Item[]
  /** Text before the contact link at the bottom. */
  contactPrompt?: string
  contactCta?: { label: string; href: string }
  /** Heading element — use "h1" when this is the page's main heading. */
  as?: "h1" | "h2"
  className?: string
}

const defaultItems: Faq01Item[] = [
  {
    question: "How does the 14-day free trial work?",
    answer:
      "Every plan starts with a full-featured 14-day trial — no credit card required. You get everything in the plan you pick, and we'll remind you before the trial ends. If you don't upgrade, your account simply drops to read-only until you do.",
  },
  {
    question: "Can I change plans later?",
    answer:
      "Yes. You can upgrade, downgrade or switch billing intervals at any time from your dashboard. Upgrades take effect immediately and we prorate the difference; downgrades apply at the start of your next billing cycle.",
  },
  {
    question: "What counts as a monthly page view?",
    answer:
      "A page view is a single load of any page you publish with Lumen. We count unique loads, not visitors — a visitor browsing five pages counts as five views. Bot and crawler traffic is filtered out automatically and never counts against your quota.",
  },
  {
    question: "Do you offer discounts for startups or nonprofits?",
    answer:
      "We do. Early-stage startups get 50% off Pro for their first year, and registered nonprofits and open-source projects get 30% off any plan, forever. Reach out from your work email and we'll set it up within a day.",
  },
  {
    question: "How do you handle data privacy?",
    answer:
      "All data is encrypted in transit and at rest, and we're fully GDPR and CCPA compliant. On Pro and above you can choose EU-only data residency. We never sell or share your data — you can export or permanently delete everything at any time.",
  },
  {
    question: "Can I cancel anytime?",
    answer:
      "Absolutely. Cancel in two clicks from your billing settings — no emails, no phone calls. Your plan stays active until the end of the period you've paid for, and you can export all of your data before or after cancelling.",
  },
  {
    question: "What kind of support is included?",
    answer:
      "Starter includes community support with responses typically within a day. Pro adds priority email support with a 4-hour first-response target during business hours. Enterprise customers get a dedicated success manager and a shared Slack channel.",
  },
]

export function Faq01({
  eyebrow = "FAQ",
  title = "Frequently asked questions",
  description = "Everything you need to know about Lumen, billing and your data. Can't find what you're looking for? Our team is one message away.",
  items = defaultItems,
  contactPrompt = "Still have questions?",
  contactCta = { label: "Talk to our team", href: "#" },
  as: Heading = "h2",
  className,
}: Faq01Props) {
  return (
    <section className={cn("bg-background px-6 py-24 md:py-32", className)}>
      <div className="mx-auto max-w-3xl">
        <div className="text-center">
          <Reveal>
            <p className="text-sm font-medium tracking-widest text-primary uppercase">
              {eyebrow}
            </p>
          </Reveal>
          <Reveal delay={0.1}>
            <Heading className="mt-4 text-balance font-heading text-4xl font-semibold tracking-tight md:text-5xl">
              {title}
            </Heading>
          </Reveal>
          <Reveal delay={0.2}>
            <p className="mx-auto mt-5 max-w-xl text-pretty text-muted-foreground md:text-lg">
              {description}
            </p>
          </Reveal>
        </div>

        <Reveal delay={0.3} className="mt-12 md:mt-14">
          <Accordion defaultValue={[0]} className="rounded-2xl border bg-card px-6">
            {items.map((item, index) => (
              <AccordionItem key={index} value={index}>
                <AccordionTrigger className="py-5 text-base font-medium">
                  {item.question}
                </AccordionTrigger>
                <AccordionContent className="pb-5 text-base text-muted-foreground">
                  {item.answer}
                </AccordionContent>
              </AccordionItem>
            ))}
          </Accordion>
        </Reveal>

        <Reveal delay={0.4}>
          <p className="mt-10 text-center text-sm text-muted-foreground">
            {contactPrompt}{" "}
            <a
              href={contactCta.href}
              className="inline-flex items-center gap-1 font-medium text-primary underline-offset-4 hover:underline"
            >
              {contactCta.label}
              <ArrowRight className="size-3.5" />
            </a>
          </p>
        </Reveal>
      </div>
    </section>
  )
}