Installation
Usage
import { FAQScrollAccordion } from "@/components/ruixen/faq-scroll-accordion";
import type { FAQItem } from "@/components/ruixen/faq-scroll-accordion";
const items: FAQItem[] = [
{
question: "What is Ruixen UI?",
answer: "A curated collection of production-ready components.",
},
{
question: "Is it open-source?",
answer: "Yes, fully open-source under the MIT license.",
},
];
export default function MyFAQ() {
return <FAQScrollAccordion items={items} />;
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | "Frequently asked questions" | Section heading |
subtitle | string | "Everything you need to know." | Subtitle below heading |
items | FAQItem[] | Built-in defaults | Array of FAQ items |
scrollDriven | boolean | true | Enable scroll-driven auto-open |
defaultActive | number | null | 0 | Initially open item index |
className | string | — | Additional classes on root section |
FAQItem
interface FAQItem {
question: string;
answer: string;
}Self-Contained Scroll Container
The component creates its own scrollable container (max-h-80, overflow-y-auto) with the IntersectionObserver scoped to it via root: scrollContainer. This means:
- Page scroll has zero effect on which item opens — only scrolling within the component's container triggers changes
- Works in iframes and previews — the container IS the scroll context
- Gradient masks at top and bottom (5%) indicate scrollable content
- Hidden scrollbar for clean aesthetics (
scrollbar-width: none)
The center detection zone is the middle 20% of the container (rootMargin: "-40% 0px -40% 0px"). An item must reach this zone to auto-open — slight scrolling won't trigger changes.
Click Behavior
Clicking an item:
- Opens/closes it immediately
- Smooth-scrolls the container to center the clicked item
- Pauses scroll-driven behavior for 3 seconds so the observer doesn't override user intent
Animation Details
- Grid expand —
grid-template-rows: 0fr → 1frfor smooth height animation (450ms, expo deceleration) - Answer choreography — text fades in + slides up with 100ms delay after container opens
- Chevron rotation — inline SVG rotates 180deg with expo easing
- Close is faster — text fades in 150ms, container collapses in 300ms
Features
- Zero dependencies — no GSAP, no framer-motion, no lucide-react
- Self-contained scroll context — immune to page scroll
- Click-to-center with scroll pause
- Proper TypeScript interfaces
- Theme-aware via CSS custom properties
- Accessible — semantic buttons, keyboard navigable

