Features Section 1

Frequently asked questions

We are here to help you with any questions you may have. If you don't find what you need, please contact us atsupport@acme.com

Installation Steps

  1. Install Dependencies: Install the required dependencies using npm:

    npm install framer-motion
    
  2. Copy this Component

FaqSection.tsx
"use client";
import React, { useState } from "react";
import { motion, AnimatePresence, useAnimation } from "framer-motion";
import { ChevronDown } from "lucide-react";
import { useInView } from "framer-motion";
import { useEffect, useRef } from "react";

const faqs = [
  {
    question: "What can I use it for?",
    answer:
      "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ut metus ligula. Proin vehicula velit quis justo facilisis, in facilisis dolor interdum.",
  },
  {
    question: "What sections are available?",
    answer:
      "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ut metus ligula. Proin vehicula velit quis justo facilisis, in facilisis dolor interdum.",
  },
  {
    question: "Do you accept refunds?",
    answer:
      "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ut metus ligula. Proin vehicula velit quis justo facilisis, in facilisis dolor interdum.",
  },
  {
    question: "Can I cancel my subscription?",
    answer:
      "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ut metus ligula. Proin vehicula velit quis justo facilisis, in facilisis dolor interdum.",
  },
];

const FAQItem = ({
  question,
  answer,
  isOpen,
  toggleOpen,
}: {
  question: string;
  answer: string;
  isOpen: boolean;
  toggleOpen: () => void;
}) => {
  return (
    <div className="border-b border-gray-700">
      <button
        className="w-full py-6 flex justify-between items-center text-left"
        onClick={toggleOpen}
      >
        <span className="text-gray-900 dark:text-gray-200 font-semibold">
          {question}
        </span>
        <ChevronDown
          className={`text-gray-500 dark:text-gray-400 transition-transform duration-300 ${
            isOpen ? "transform rotate-180" : ""
          }`}
        />
      </button>
      <AnimatePresence>
        {isOpen && (
          <motion.div
            initial={{ height: 0, opacity: 0 }}
            animate={{ height: "auto", opacity: 1 }}
            exit={{ height: 0, opacity: 0 }}
            transition={{ duration: 0.3 }}
            className="overflow-hidden"
          >
            <p className="pb-6 text-muted-foreground dark:text-gray-400">
              {answer}
            </p>
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  );
};

const containerVariants = {
  hidden: { opacity: 0 },
  visible: {
    opacity: 1,
    transition: {
      staggerChildren: 0.5,
      delayChildren: 0.4,
    },
  },
};

const itemVariants = {
  hidden: { opacity: 0, y: 20, filter: "blur(3px)" },
  visible: {
    filter: "blur(0px)",
    opacity: 1,
    y: 0,
    transition: {
      duration: 0.8,
      ease: [0.25, 0.1, 0.25, 1],
    },
  },
};

const FaqSection = (): JSX.Element => {
  const [openIndex, setOpenIndex] = useState(-1);
  const controls = useAnimation();
  const divRef = useRef(null);
  const IsInView = useInView(divRef);

  useEffect(() => {
    if (IsInView) {
      controls.start("visible");
    }
  }, [IsInView]);

  return (
    <motion.section
      className="w-full max-w-7xl mx-auto py-24 px-8"
      ref={divRef}
      variants={containerVariants}
      initial="hidden"
      animate={controls}
    >
      <div className="w-full max-w-3xl mx-auto">
        <motion.div
          initial={{ opacity: 0, y: 20 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 0.5 }}
          className="grid gap-y-8"
        >
          <div className="grid gap-y-4">
            <motion.h1
              className="text-5xl font-bold text-center bg-gradient-to-b from-foreground to-muted-foreground dark:from-white dark:to-muted bg-clip-text text-transparent tracking-tight pb-2"
              variants={itemVariants}
            >
              Frequently asked questions
            </motion.h1>
            <motion.p
              className="text-base text-muted-foreground text-center max-w-lg mx-auto grid grid-flow-row"
              variants={itemVariants}
            >
              We are here to help you with any questions you may have. If you
              don't find what you need, please contact us at
              <span className="text-primary underline">support@acme.com</span>
            </motion.p>
          </div>
          <div>
            {faqs.map((faq, index) => (
              <motion.div variants={itemVariants} key={index}>
                <FAQItem
                  key={index}
                  question={faq.question}
                  answer={faq.answer}
                  isOpen={index === openIndex}
                  toggleOpen={() =>
                    setOpenIndex(index === openIndex ? -1 : index)
                  }
                />
              </motion.div>
            ))}
          </div>
        </motion.div>
      </div>
    </motion.section>
  );
};

export default FaqSection;