Retour au catalogue
FAQ 2 Columns Sticky
FAQ en 2 colonnes avec titre sticky a gauche et questions en accordion a droite.
faqsimple Both Responsive a11y
editorialelegantsaasagencyuniversalsplitsticky
Theme
"use client";
import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { ChevronDown } from "lucide-react";
interface FaqItem {
question: string;
answer: string;
}
interface Faq2ColStickyProps {
badge?: string;
title?: string;
subtitle?: string;
items?: FaqItem[];
}
const ease: [number, number, number, number] = [0.16, 1, 0.3, 1];
export default function Faq2ColSticky({
badge = "FAQ",
title = "Vous avez des questions ?",
subtitle = "",
items = [],
}: Faq2ColStickyProps) {
const [openIndex, setOpenIndex] = useState<number | null>(0);
return (
<section
className="py-20 lg:py-28"
style={{ background: "var(--color-background)" }}
>
<div className="mx-auto max-w-6xl px-6">
<div className="grid lg:grid-cols-5 gap-14 lg:gap-20">
{/* Left - sticky */}
<div className="lg:col-span-2 lg:sticky lg:top-24 lg:self-start">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, ease }}
viewport={{ once: true }}
>
{badge && (
<span
className="inline-block mb-4 text-xs font-medium tracking-widest uppercase"
style={{ color: "var(--color-accent)" }}
>
{badge}
</span>
)}
<h2
className="text-3xl md:text-4xl font-bold"
style={{ color: "var(--color-foreground)" }}
>
{title}
</h2>
{subtitle && (
<p
className="mt-4 text-base leading-relaxed"
style={{ color: "var(--color-foreground-muted)" }}
>
{subtitle}
</p>
)}
</motion.div>
</div>
{/* Right - accordion */}
<div className="lg:col-span-3">
{items.map((item, i) => {
const isOpen = openIndex === i;
return (
<motion.div
key={i}
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, ease, delay: i * 0.04 }}
viewport={{ once: true }}
style={{
borderBottom: "1px solid var(--color-border)",
}}
>
<button
onClick={() => setOpenIndex(isOpen ? null : i)}
className="w-full flex items-center justify-between gap-4 py-6 text-left"
>
<span
className="text-base font-medium"
style={{
color: "var(--color-foreground)",
}}
>
{item.question}
</span>
<motion.div
animate={{ rotate: isOpen ? 180 : 0 }}
transition={{ duration: 0.25 }}
className="flex-shrink-0"
>
<ChevronDown
size={18}
style={{ color: "var(--color-foreground-muted)" }}
/>
</motion.div>
</button>
<AnimatePresence initial={false}>
{isOpen && (
<motion.div
initial={{ height: 0, opacity: 0 }}
animate={{ height: "auto", opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
transition={{ duration: 0.3, ease }}
className="overflow-hidden"
>
<p
className="pb-6 text-sm leading-relaxed"
style={{ color: "var(--color-foreground-muted)" }}
>
{item.answer}
</p>
</motion.div>
)}
</AnimatePresence>
</motion.div>
);
})}
</div>
</div>
</div>
</section>
);
}