FAQ
FAQ stands for "frequently asked questions" — the list of things people keep asking, answered once in the place they will look.
Structurally it is an accordion, and WireKit already has a good one, so this component uses it rather than growing a second. What it adds is the part an accordion cannot know: that these rows are questions, and that search engines should be told so.
FAQ vs Accordion vs Collapsible — when to use which
- FAQ (this component) — a question list built on the accordion that also emits FAQPage structured data derived from what it renders.
- Accordion — the general coordinated group of panels (single or multiple open, card chrome) with no question semantics or schema.
- Collapsible — a single independent show/hide, or a stack of them with no coordination.
<x-wirekit::faq> emits FAQPage structured data
built from the questions it just rendered — from the visible answer, never a
second hand-written copy. Normally that duplication is your problem: you write the
accordion, then you write the JSON-LD again, and the two drift apart on the first
copy edit.
Here they cannot drift, because there is only one copy. Reword a question and the schema follows. Delete one and it leaves the schema too. The schema is made out of the visible answer rather than a copy of it.
Look at the page source of that preview and you will find a
<script type="application/ld+json"> block listing exactly those three
questions — no second list to maintain.
One FAQPage per page
A page should carry exactly one FAQPage. Two of them compete rather than
combine, and search engines may ignore both.
So if you show more than one FAQ block on a page, let one of them own the schema and turn it off on the others:
{{-- The main FAQ owns the schema --}}
<x-wirekit::faq>
<x-wirekit::faq-item question="How do I install it?">…</x-wirekit::faq-item>
</x-wirekit::faq>
{{-- A second block on the same page: same questions, no competing schema --}}
<x-wirekit::faq :schema="false">
<x-wirekit::faq-item question="Billing question">…</x-wirekit::faq-item>
</x-wirekit::faq>
Turning the schema off never changes what the reader sees — only what search engines are told.
Do not describe answers you are not showing
Only emit the schema where the questions and answers are really on the page. An
FAQPage describing content the reader cannot reach is a search-engine policy
violation, not a shortcut to rich results. This component keeps you on the right
side of that by construction — but if you hide the questions behind something the
crawler cannot open, turn schema off.
Rich answers
An answer is a slot, so it takes real markup — links, lists, emphasis:
<x-wirekit::faq-item question="Where are the docs?">
See <a href="https://docs.wirekit.app">the documentation</a>, or run
<code>php artisan wirekit:list</code> to browse every component from your terminal.
</x-wirekit::faq-item>
The same markup goes into the schema, because the schema is the rendered answer.
When the markup is too rich for the schema
Search engines accept only a limited HTML subset inside a FAQPage answer. An
answer built from nested components — anything that renders data-* attributes,
Alpine directives, or utility classes — can therefore fail rich-result validation
even though it reads perfectly on the page.
plain-text strips the markup from the schema only. The reader still sees the
full rendered answer; the schema gets the same words as text:
<x-wirekit::faq plain-text>
<x-wirekit::faq-item question="What is included?">
<x-wirekit::badge>New</x-wirekit::badge> Priority support
</x-wirekit::faq-item>
</x-wirekit::faq>
The schema answer becomes Priority support prefixed by the badge's text —
entities decoded, whitespace collapsed. It stays derived from what you
rendered, so the indexed answer can never drift away from the visible one.
For the rare case where the schema answer must differ in content rather than markup, a single item can override it outright:
<x-wirekit::faq-item question="How do refunds work?" schema-answer="Refunds are issued within 14 days.">
…the long, linked, formatted answer the reader sees…
</x-wirekit::faq-item>
Reach for schema-answer sparingly: it is hand-written copy, and hand-written
copy is what drifts.
Appearance
faq defaults to the accordion's flush variant and lg size, because an FAQ
almost always sits inline in page content where the surrounding section already
draws the chrome — a second border there only competes with it. Pass variant
or size to override; they go straight through to the accordion. Use the boolean
multiple prop to let more than one entry stay open at once (faq exposes it
instead of the accordion's mode string).
<x-wirekit::faq variant="separated" size="md" multiple>
…
</x-wirekit::faq>
Props
<x-wirekit::faq>
| Prop | Type | Default | Description |
|---|---|---|---|
label |
string |
'Frequently asked questions' |
Accessible name for the question list. |
variant |
string |
'flush' |
Passed to the accordion: flush, bordered, separated. |
size |
string |
'lg' |
Passed to the accordion: md, lg. |
multiple |
bool |
false |
Let several answers stand open at once. Default is one at a time. |
schema |
bool |
true |
Emit FAQPage JSON-LD for the questions rendered here. |
plainText |
bool |
false |
Strip markup from the schema answer text (entities decoded, whitespace collapsed). The visible answer is untouched. |
scope |
string|null |
null |
Class-scope override. |
<x-wirekit::faq-item>
| Prop | Type | Default | Description |
|---|---|---|---|
question |
string |
'' |
The question. Rendered as the trigger and recorded for the schema. |
schemaAnswer |
string|null |
null |
Replace this item's schema answer outright, for the rare case where it must differ from the visible one in content. Prefer plain-text on the faq. |
id |
string|null |
null |
Explicit item id. Generated when omitted. |
scope |
string|null |
null |
Class-scope override. |
Accessibility
The accordion's accessibility is inherited whole, not reimplemented: each question
is a real <button> inside a heading with aria-expanded and aria-controls, and
each answer is a role="region" labeled by its question. Keyboard support comes
from the same place.
An empty question or an empty answer is dropped from the schema rather than
emitted as a node with no name — a Question with nothing to ask is not
something to tell a search engine about.
Keyboard Interaction
Inherited from accordion — Tab moves between questions,
Enter / Space opens and closes the focused one.
Structured data & AI search (GEO)
Who reads this schema now — LLMs and AI answer engines
The FAQPage markup is consumed mostly by LLM-based answer engines and AI
crawlers today — the AI agents and AI search overviews that read structured Q&A to
extract and cite answers. That is generative engine optimization (GEO), and FAQ is
among the schema types those engines cite most often; being
machine-readable, it reaches an AI agent that only sees your HTML and cannot run the
JavaScript that reveals the accordion. Google's own FAQ rich result, by contrast,
is retired — narrowed to authoritative government and health sites in 2023, then
removed in 2026 — so the payoff today is visibility in AI answers plus a schema built
from the visible answer, not a Google rich result.