FAQs
Two-column accordion of frequently asked questions.
Frequently asked
import { FAQs } from '@/foundations/blocks/faqs';
export default function FAQsPreview() {
return (
<FAQs
title="Frequently asked"
questions={[
{
question: 'Is everything copy-paste?',
answer:
'Yes. Every block ships its own source. You drop the file in your project and edit it like any other component.',
},
{
question: 'Do I need to install a runtime?',
answer:
'No. Each block depends only on the Playstack primitives it composes, all of which are also copy-paste.',
},
{
question: 'How are blocks versioned?',
answer:
"They aren't — your copy is the version. If a block changes upstream and the change matters, the changelog tells you what to update.",
},
{
question: 'Can I theme blocks?',
answer:
'Yes. Blocks read the same theme tokens primitives use, so swapping the theme swaps every block in lockstep.',
},
]}
/>
);
}
export const meta = {
layout: 'fullscreen',
}; Dependencies
Source Code
import { ChevronDown } from '@untitledui-pro/icons/solid';
import { Container } from '@/components/container';
import { Disclosure } from '@/components/disclosure';
import { cn } from '@/lib/utils/classnames';
interface FAQItem {
question: React.ReactNode;
answer: React.ReactNode;
}
interface FAQsProps
extends Omit<React.ComponentPropsWithRef<'section'>, 'title'> {
title: React.ReactNode;
questions: FAQItem[];
/** Two-column grid on `lg+`. Defaults to `true`. */
twoColumn?: boolean;
}
const FAQs = ({
ref,
className,
title,
questions,
twoColumn = true,
...rest
}: FAQsProps) => (
<section
ref={ref}
className={cn('w-full py-16 md:py-24', className)}
{...rest}
>
<Container>
<h2 className="text-balance text-4xl md:text-5xl">{title}</h2>
<ul
className={cn(
'mt-10 grid grid-cols-1 gap-x-12',
twoColumn && 'lg:grid-cols-2'
)}
>
{questions.map((q, i) => (
<li key={i} className="border-border border-t last:border-b">
<Disclosure>
<Disclosure.Trigger
className={cn(
'flex w-full items-center justify-between gap-2 py-4 text-left text-xl',
'transition-colors duration-(--duration-hover) ease-out',
'hover:text-foreground-secondary'
)}
>
<span>{q.question}</span>
<ChevronDown
className={cn(
'size-4 shrink-0 text-foreground-secondary',
'transition-transform duration-(--duration-hover) ease-out',
'group-data-[state=open]:rotate-180'
)}
/>
</Disclosure.Trigger>
<Disclosure.Content className="pb-4 text-foreground-secondary text-lg">
{q.answer}
</Disclosure.Content>
</Disclosure>
</li>
))}
</ul>
</Container>
</section>
);
export type { FAQItem, FAQsProps };
export { FAQs }; FAQs is a two-column accordion of common questions. Each row uses
Disclosure so it animates open/closed and keeps focus management correct.
Anatomy
<FAQs
title="Frequently asked"
questions={[
{ question: 'Is it copy-paste?', answer: 'Yes — that is the contract.' },
{ question: 'Do I need to install a runtime?', answer: 'No.' },
]}
/>
API Reference
Extends the section element.
| Prop | Default | Type |
|---|---|---|
title * | - | ReactNode |
questions * | - | FAQItem[] |
twoColumn | true | boolean |
FAQItem
interface FAQItem {
question: React.ReactNode;
answer: React.ReactNode;
}
Examples
Default
Frequently asked
import { FAQs } from '@/foundations/blocks/faqs';
export default function FAQsPreview() {
return (
<FAQs
title="Frequently asked"
questions={[
{
question: 'Is everything copy-paste?',
answer:
'Yes. Every block ships its own source. You drop the file in your project and edit it like any other component.',
},
{
question: 'Do I need to install a runtime?',
answer:
'No. Each block depends only on the Playstack primitives it composes, all of which are also copy-paste.',
},
{
question: 'How are blocks versioned?',
answer:
"They aren't — your copy is the version. If a block changes upstream and the change matters, the changelog tells you what to update.",
},
{
question: 'Can I theme blocks?',
answer:
'Yes. Blocks read the same theme tokens primitives use, so swapping the theme swaps every block in lockstep.',
},
]}
/>
);
}
export const meta = {
layout: 'fullscreen',
}; Previous
CTA Banner
Next
Hero