Innovations

FAQ Accordion

FAQ section using native HTML <details>/<summary> accordion. 6 sample questions about web design services. Section header and a bottom CTA link. No Radix dependency.

Preview

Source

tsx
"use client";

import { motion } from "framer-motion";
import { MessageCircle } from "lucide-react";

const faqs = [
  {
    question: "How long does a typical website project take?",
    answer:
      "Most projects are completed within 4–8 weeks from kickoff to launch. The timeline depends on the scope: a focused landing page can be live in 2 weeks, while a full multi-page site with custom integrations typically takes 6–10 weeks. We'll give you a detailed timeline after our discovery call.",
  },
  {
    question: "What's included in your web design service?",
    answer:
      "Every project includes discovery & strategy, UX wireframes, high-fidelity design mockups, responsive development, CMS setup, performance optimization, SEO foundations, and a 30-day post-launch support window. We handle everything from concept to code.",
  },
  {
    question: "Do you work with existing websites or only build new ones?",
    answer:
      "Both. We take on redesigns, CRO audits, and incremental improvements to existing sites, as well as greenfield builds. If your current site has strong content or SEO equity, we'll preserve what's working and elevate what's not.",
  },
  {
    question: "What platforms and technologies do you use?",
    answer:
      "We specialize in Astro, Next.js, Webflow, and custom React applications. For e-commerce, we work with Shopify. CMS options include Sanity, Contentful, and Notion-as-CMS for simpler needs. We'll recommend the right stack for your goals and team's capabilities.",
  },
  {
    question: "How does pricing work?",
    answer:
      "We offer fixed-scope project pricing so you always know what you're paying upfront — no hourly surprises. Projects start at $4,500 for focused landing pages and scale based on complexity. We also offer monthly retainers for teams who want ongoing design and development support.",
  },
  {
    question: "What do you need from us to get started?",
    answer:
      "Typically: access to your brand guidelines (or an open brief if you're rebranding), content for the pages we're building (or notes on what you want to say), and a primary point of contact on your team. We'll guide you through everything else during onboarding.",
  },
];

export default function FaqAccordion() {
  return (
    <section className="py-20 sm:py-28 bg-background">
      <div className="container mx-auto px-6 max-w-3xl">
        {/* Header */}
        <motion.div
          initial={{ opacity: 0, y: 20 }}
          whileInView={{ opacity: 1, y: 0 }}
          viewport={{ once: true }}
          transition={{ duration: 0.6 }}
          className="text-center mb-12"
        >
          <span className="text-sm font-semibold uppercase tracking-widest text-primary">
            Got questions?
          </span>
          <h2 className="mt-3 text-3xl sm:text-4xl font-extrabold tracking-tight text-foreground">
            Frequently asked questions
          </h2>
          <p className="mt-4 text-muted-foreground text-lg">
            Everything you need to know before getting started. Can't find what
            you're looking for?{" "}
            <a href="#" className="text-primary underline underline-offset-4 hover:no-underline">
              Chat with us.
            </a>
          </p>
        </motion.div>

        {/* FAQ accordion using <details>/<summary> */}
        <motion.div
          initial={{ opacity: 0 }}
          whileInView={{ opacity: 1 }}
          viewport={{ once: true }}
          transition={{ duration: 0.5, delay: 0.1 }}
          className="divide-y divide-border border border-border rounded-2xl overflow-hidden"
        >
          {faqs.map((faq, i) => (
            <motion.details
              key={i}
              initial={{ opacity: 0, y: 8 }}
              whileInView={{ opacity: 1, y: 0 }}
              viewport={{ once: true }}
              transition={{ duration: 0.4, delay: 0.05 * i }}
              className="group bg-card"
            >
              <summary className="flex items-center justify-between gap-4 px-6 py-5 cursor-pointer list-none select-none hover:bg-muted/40 transition-colors">
                <span className="font-semibold text-foreground text-base leading-snug">
                  {faq.question}
                </span>
                {/* Chevron indicator */}
                <span
                  className="shrink-0 w-6 h-6 rounded-full border border-border flex items-center justify-center text-muted-foreground transition-transform duration-300 group-open:rotate-45"
                  aria-hidden
                >
                  <svg
                    xmlns="http://www.w3.org/2000/svg"
                    width="12"
                    height="12"
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    strokeWidth="2.5"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                  >
                    <path d="M12 5v14M5 12h14" />
                  </svg>
                </span>
              </summary>
              <div className="px-6 pb-6 pt-2 text-muted-foreground leading-relaxed text-sm sm:text-base">
                {faq.answer}
              </div>
            </motion.details>
          ))}
        </motion.div>

        {/* Bottom CTA */}
        <motion.div
          initial={{ opacity: 0, y: 16 }}
          whileInView={{ opacity: 1, y: 0 }}
          viewport={{ once: true }}
          transition={{ duration: 0.5, delay: 0.3 }}
          className="mt-10 flex items-center justify-center gap-3 text-sm text-muted-foreground"
        >
          <MessageCircle className="w-4 h-4" />
          Still have questions?{" "}
          <a href="#" className="text-primary font-semibold hover:underline underline-offset-4">
            Book a 15-min call →
          </a>
        </motion.div>
      </div>
    </section>
  );
}
Claude Code Instructions

CLI Install

npx innovations add faq-accordion

Where to use it

Place near the bottom of landing pages, typically above the footer CTA and below testimonials. In Astro (src/pages/index.astro): import FaqAccordion from '../components/innovations/content/faq-accordion'; <FaqAccordion client:visible /> In Next.js (app/page.tsx): import FaqAccordion from '@/components/innovations/content/faq-accordion'; Edit the faqs array at the top of the component. Each FAQ is { question: string, answer: string }. The component uses native <details>/<summary> HTML for the accordion — no JavaScript needed for open/close behavior, which means it works with SSR and without hydration for basic functionality. The group-open:rotate-45 Tailwind class animates the + icon into an × when the item is open. This requires the 'group' class on <details> — already included.