Faq
Questions and answers in a titled section: groups to switch between, a search that filters as you type, a link to each question and a way to ask another.
import { Faq } from "@butteryui/react";Demo
Questions, answered
What people ask the roastery most.
Still have a question?
Write to hello@halfmoon.example and Rosa or Theo will answer within a day.
When to use it
Use it for
- A store's or an app's questions and answers, as a page of their own or a section of a longer one
- A help center's questions in groups people switch between, with a search across all of them
- A few questions under a product, a plan or a form
Not for
- Guides or articles that run longer than an answer: give them pages of their own
- Parts of a record or a form that aren't questions, such as an account's settings: use Accordion
- Searching a whole site or app: use CommandSearch
Examples
Coffee page
A coffee's own page ends with three short questions about it: no groups, no search.
Good to know
Help center
A help center whose page keeps the open questions, so its popular links open one in whichever topic it's in.
Help with Deckhand
Answers about making, presenting and sharing decks.
Still have a question?
Write to help@deckhand.example and we'll answer within a working day.
Layouts
One set of questions in each layout and each look of its rows.
Wholesale
For cafés and offices that pour our coffee.
Nothing found
A search that finds nothing shows what to try and a way back to every question.
Store questions
The shop's questions beside their intro: topics in tabs, a search across them, a link to one answer and a way to write in.
Questions, answered
What people ask us most. New here? Start with when your coffee arrives.
Still wondering about something?
Write to hello@halfmoon.example and Rosa or Theo will answer within a day.
Variants and states
layout="stacked"
One column at most 720px wide: the intro, the questions, then the contact.
Questions, answered
What people ask the roastery most.
Still have a question?
Write to hello@halfmoon.example and Rosa or Theo will answer within a day.
layout="split"
The intro and the contact beside the questions from 640px of room, stacked under that.
Questions, answered
What people ask the roastery most.
Still have a question?
Write to hello@halfmoon.example and Rosa or Theo will answer within a day.
layout="two-column"
The questions in two columns under the intro from 640px of room, one under that.
Questions, answered
What people ask the roastery most.
Still have a question?
Write to hello@halfmoon.example and Rosa or Theo will answer within a day.
With a search
The search looks through every group's questions and answers as you type, marking what matches; when nothing does, a way to clear it shows in their place.
Props
Faq
| Prop | Type | Default | Description |
|---|---|---|---|
title | ReactNode | The heading over the questions, such as "Questions, answered". | |
intro | ReactNode | A line or two under the heading. | |
titleAs | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "h2" | What the heading renders as. Defaults to "h2"; the questions are headings a level below it. |
questionsrequired | readonly FaqQuestion[] | The questions, in the order they show. | |
groups | readonly FaqGroup[] | The groups the questions are in, in tab order. With two or more, tabs switch between them; each question names its own. | |
value | readonly string[] | The open questions' ids. Pair with onValueChange to control them. | |
defaultValue | readonly string[] | The questions open at first when uncontrolled. Defaults to none. | |
onValueChange | ((value: readonly string[]) => void) | Called with the open questions' ids each time one opens or closes. | |
group | string | The group shown. Pair with onGroupChange to control it. | |
defaultGroup | string | The group shown at first when uncontrolled. Defaults to the first. | |
onGroupChange | ((group: string) => void) | Called with the group a person shows: by its tab, or by following a link to a question in it. | |
search | boolean | false | Shows a search field over the questions that filters every group's as you type. Defaults to false. |
layout | "stacked" | "split" | "two-column" | "stacked" | How the parts are arranged: "stacked" (the default), one column at most 720px wide; "split", the intro
and contact beside the questions; or "two-column", the questions in two columns. Split and two columns
take 640px of room and stack under that. |
variant | "divided" | "contained" | "cards" | "plain" | "divided" | How the questions are drawn, as Accordion's variant. Defaults to "divided". |
size | "sm" | "md" | "lg" | "md" | How big the questions are, as Accordion's size. Defaults to "md". |
contact | ReactNode | What closes the FAQ, such as a Faq.Contact with a way to ask a question it doesn't answer. | |
labels | Partial<FaqLabels> | Its words, for another language or your own. |
It also takes Omit<ComponentPropsWithRef<"div">, "title" | "defaultValue" | "children">.
Faq.Contact
| Prop | Type | Default | Description |
|---|---|---|---|
title | ReactNode | "Still have a question?" | The heading. Defaults to "Still have a question?". |
description | ReactNode | A line under it, such as who answers and how soon. | |
actions | ReactNode | The ways to ask, such as a Button with asChild around a link to an email address. | |
titleAs | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "h3" | What the heading renders as. Defaults to "h3". |
It also takes Omit<ComponentPropsWithRef<"div">, "title" | "children">.
FaqQuestion
One question and its answer.
| Field | Type | Default | Description |
|---|---|---|---|
idrequired | string | Identifies the question: the anchor that opens it and scrolls to it from a #id link, and what value
holds while it's open. Unique on the page, as any element id is. | |
questionrequired | string | The question, as its trigger's words. | |
answerrequired | ReactNode | The answer: words, or anything else, such as a paragraph with a link in it. | |
group | string | The value of the group it's in, when the FAQ has groups. | |
keywords | string | More words the search matches, such as the words people use for it: "refund" for a returns question. |
FaqGroup
A group of questions, such as a topic, that a tab shows.
| Field | Type | Default | Description |
|---|---|---|---|
valuerequired | string | Identifies the group: what each of its questions names as its group. | |
labelrequired | string | The tab's words, such as "Orders and shipping". |
FaqLabels
The words an FAQ shows, for another language or your own.
| Field | Type | Default | Description |
|---|---|---|---|
searchrequired | string | Names the search field and shows as its placeholder, such as "Search questions". | |
groupsrequired | string | Names the tabs for screen readers, such as "Topics". | |
resultsrequired | (count: number) => string | How many questions match a search, read out as the results change, such as "3 questions match". | |
noResultsrequired | (search: string) => string | The title of what shows when nothing matches, such as No questions match "decaf". | |
noResultsHintrequired | string | The line under it. | |
showAllrequired | string | The button under it that clears the search, such as "Show all questions". |
Accessibility
Its title is a heading (an h2 unless titleAs says otherwise) and each question is a button in a heading a level below it, named by the question (and in search results by its group after it), as in Accordion. The search field is a searchbox named by its label; as you type, a polite status says how many questions match, and the matching words are marked. The groups are tabs in a tablist named by labels.groups. A link to a question's #id opens it and moves focus to it, as following an anchor does, without a ring; the no-results message's "Show all questions" clears the search and puts focus back in the field.
| Keys | What they do |
|---|---|
| Tab | Moves through the search field, the chosen tab, each question and the contact, in that order |
| Escape | Clears the search from the search field, keeping focus there |
| Arrow Right or Arrow Left | Moves between the tabs and shows that group's questions |
| Arrow Down or Arrow Up | Moves to the next or previous question, wrapping at the ends of a column |
| Home or End | Moves to the first or last question |
| Enter or Space | Opens or closes the question whose trigger has focus |
Motion
It changes shape as one surface, on `spring.smooth`, or `spring.morph` for a big change, rather than closing and reopening.
With reduced motion: A question opens and closes at once and its chevron turns over at once; its answer fades in and out in 100ms.
Layout
It's its own size container and fills its container's width. Stacked, it's one column at most 720px wide: the intro, the questions 48px under it (64 on a page from 1024px wide), then the contact 32px under them. From 640px of room, split puts the intro and the contact in a column a third wide (240px at least) beside the questions, 48px apart, and two-column lays the questions out in two columns; under 640 both stack as stacked does. The search field fills the questions' column (at most 600px wide in two columns), the tabs fold the groups that don't fit into a More menu, and questions wrap instead of truncating. Faq.Contact puts its actions beside its words from 480px wide and under them when it's narrower.
Related
See it in the Halfmoon shop demo.