Skip to content
Facade UI
blockmotion

FAQ accordion (motion)

The FAQ accordion, with rows appearing as you scroll to them. The open and close animation works without JavaScript.

Open in v0 (opens in a new tab)

This is the animated version of FAQ accordion. The static version looks the same with JavaScript turned off.

Preview

Open full width (opens in a new tab)
Preview width

Installation

Package manager
pnpm dlx shadcn@latest add https://facadeui.dev/r/faq-accordion-motion.json

This component needs faq-accordion, motion-primitives. The CLI installs them for you.

Usage

This is the code for the preview above. To install it as a file, run npx shadcn@latest add @facade/faq-accordion-motion-demo.

demos/faq-accordion-motion.tsx
"use client"

/**
 * The `faq-accordion` demo, with the motion variant swapped in.
 *
 * Identical props: the motion variant only changes which slot components
 * the static section renders through.
 *
 * `"use client"` is required here, not incidental: the motion variant is a
 * client component, and icon components cannot cross a server-to-client
 * boundary as props. See the note on `IconComponent`.
 */

import { FaqAccordionMotion } from "@registry/sections/faq-accordion-motion"

import { FAQS } from "./content"

export function Demo() {
  return (
    <FaqAccordionMotion
      eyebrow="FAQ"
      title="Questions, answered"
      items={FAQS}
      defaultOpen={["faq-is-facade-ui-free"]}
      align="center"
      schemaOrg
    />
  )
}

Source

These are the files the CLI copies into your project.

components/sections/faq-accordion-motion.tsx
"use client"

/**
 * FaqAccordionMotion — the FAQ with its rows revealed as they scroll in.
 *
 * The open/close animation is *not* what this adds: Base UI plus the CSS height
 * transition already handles that, without JavaScript. What the motion variant
 * contributes is the entrance of the list itself.
 *
 * Dependencies: react, @/components/motion/slots,
 * @/components/sections/faq-accordion.
 */

import type { ReactNode } from "react"

import { StaggerBlock } from "@/components/motion/slots"
import { Stagger } from "@/components/motion/stagger"
import { FaqAccordion, type FaqAccordionProps } from "@/components/sections/faq-accordion"

function RevealStack({
  className,
  children,
}: {
  className?: string
  children?: ReactNode
}) {
  return (
    <Stagger className={className} stagger={0.05}>
      {children}
    </Stagger>
  )
}

export type FaqAccordionMotionProps = Omit<FaqAccordionProps, "listAs" | "itemAs">

export function FaqAccordionMotion(props: FaqAccordionMotionProps) {
  return <FaqAccordion {...props} listAs={RevealStack} itemAs={StaggerBlock} />
}

Props

FaqAccordionMotionProps

Extends Omit<FaqAccordionProps, "listAs" | "itemAs">.