FAQs
A marketing-ready frequently-asked-questions section built on the Accordion. It pairs a header with a single-expand question list and an optional contact CTA, in a centered stack or a sticky two-column split.
Installation#
Usage#
import {
Faqs,
FaqsHeader,
FaqsTitle,
FaqsDescription,
FaqsList,
FaqsItem,
FaqsFooter,
} from "@/components/ui/faqs"
export function Example() {
return (
<Faqs>
<FaqsHeader>
<FaqsTitle>Frequently asked questions</FaqsTitle>
<FaqsDescription>Everything you need to know.</FaqsDescription>
</FaqsHeader>
<FaqsList>
<FaqsItem question="Is Koala UI free to use?">
The core library is free under a permissive license.
</FaqsItem>
</FaqsList>
</Faqs>
)
}Stacked layout#
The default layout="stacked" centers the header above a width-constrained list. It is the classic centered FAQ, ideal at the foot of a landing page. Set a defaultValue on FaqsList (matching a FaqsItem value) to open the first answer so the section never reads as an empty stack of triggers.
Split layout#
Set layout="split" for a two-column grid: a header column that stays sticky while the list scrolls beside it (the Stripe / Linear FAQ). The columns stack on mobile, and FaqsFooter spans both columns underneath.
Grouped by topic#
For a long, categorized help center, slot FaqsGroups between the header and footer. Each takes a title (an <h3> under the section <h2>) and an optional description, then wraps its own questions, so the page reads header → topic → questions → topic. Each group owns its own list, so single-expand is scoped to the topic and the hairline dividers reset at every boundary. It defaults to the borderless minimal list, and still forwards every FaqsList prop (variant, defaultValue, iconPosition, …).
Landing scale#
size="lg" on Faqs is the landing-page FAQ: topic headings big enough to scan the page by, and every list inside defaults to the Accordion's own lg step (an 18px semibold question on a taller row), so questions and topics step up together. The first topic sits flush, because a landing FAQ usually has its lede in a SectionHeader above the block. Pair it with marker="plus".
List style#
FaqsList forwards straight to the Accordion, so its variant controls the chrome: card (the default: one bordered box with shared dividers), minimal (borderless rows divided by hairlines), or separated (each item its own bordered box). None of those three paints a fill, so the list takes the ground it sits on, whether that is the page or a muted band. The fourth, pill, is the chip list: a closed question hugs its own text and the open one floods into a filled card, for a short FAQ sitting beside a picture rather than filling the measure on its own.
Helpful feedback#
For a help-center / knowledge-base FAQ, set iconPosition="leading" on FaqsList to move the caret ahead of the question, and add feedback to a FaqsItem to mount a Helpful / Not helpful voting row beneath its answer. The chosen pill stays emphasized while the other dims, and an acknowledgement fades in. For full control (custom labels, an onVote handler), drop a FaqsFeedback into the answer yourself.
Footer call to action#
FaqsFooter is an optional closing row for a contact prompt. Drop a line of copy beside one of our Button components; it centers in the stacked layout and spans both columns in the split layout.
Composition#
The parts are plain composition, so a list of questions maps cleanly into FaqsItems. Give each one a stable value when you want to target it with defaultValue; omit it and a unique id is generated for you.
API reference#
| Prop | Type | Default | Description |
|---|---|---|---|
| Faqs.layout | stacked | split | stacked | Centered header above the list, or a sticky two-column grid. |
| Faqs.size | md | lg | md | Type scale. lg is the landing FAQ: bigger topic headings, and every list inside defaults to the Accordion's lg step. |
| FaqsList.variant | card | minimal | separated | card | Forwarded to Accordion: the list chrome. Borders only, never a fill. |
| FaqsList.type | single | multiple | single | Forwarded to Accordion: one open answer, or many. |
| FaqsList.collapsible | boolean | true | Forwarded to Accordion (single only): allow closing the open item. |
| FaqsList.defaultValue | string | string[] | - | Forwarded to Accordion: the item(s) open on mount. |
| FaqsList.density | comfortable | compact | comfortable | Forwarded to Accordion: row height and content inset. |
| FaqsList.iconPosition | leading | trailing | trailing | Forwarded to Accordion: caret before or after the question. |
| FaqsGroup.title | ReactNode | - | Topic heading (an <h3>) above the group's questions. |
| FaqsGroup.description | ReactNode | - | Optional supporting copy under the topic heading. |
| FaqsGroup.* | FaqsList props | variant="minimal" | Forwarded to the group's own FaqsList (variant, defaultValue, …). |
| FaqsItem.question | ReactNode | - | The question shown in the trigger row. |
| FaqsItem.value | string | auto | Unique item id. A stable id is generated when omitted. |
| FaqsItem.feedback | boolean | FaqsFeedbackProps | false | Mount a Helpful / Not helpful voting row beneath the answer. |
| FaqsFeedback.reveal | "always" | "hover" | "always" | hover opens the row with its answer instead of showing it permanently, for the always-open reading model where every answer is visible at once. The space is not reserved, so no empty gap sits under each answer; it still opens on keyboard focus, stays open once a vote is cast, and opts out entirely on touch, which has no hover. |
| FaqsFeedback.onVote | (v: "up" | "down") => void | - | Called with the chosen vote when the reader rates the answer. |
| className | string | - | Accepted by every part, merged last. |
Parts: Faqs, FaqsHeader, FaqsTitle, FaqsDescription, FaqsGroup, FaqsList, FaqsItem, FaqsFeedback, FaqsFooter. FaqsList forwards all Accordion props; each part forwards its native props and merges className last.