Purpose#
The Faq component renders frequently asked questions as nested accordions:Groups (categories): optional, collapsible when the group has a title
FAQ lists inside each group: optional, collapsible when the list has a name
Questions inside each list: each question toggles its answer
Only one question is open at a time. Server-side pagination is supported through model.Pagination.
Where it's rendered#
Placed on a page as a regular component (Components/Faq/Default.liquid). The whole section renders only when model.Groups has at least one entry.
Model shape (storefront example)#
{
"name": "Faq",
"view": "Default",
"section": "SectionA",
"settings": {
"id": "Component Id",
"cssClass": "",
"header": "Sample title",
"alignment": "Left"
},
"groups": [
{
"title": "Sample category",
"faqs": [
{
"name": "Sample name",
"items": [
{ "question": "Sample question", "answer": "<p>Sample answer</p>" }
]
}
]
}
],
"pagination": {
"pageNumber": 1,
"numberOfPages": 3,
"pageParameterName": "faqPage"
},
"translations": {
"faq": "Sample translation",
"untitled": "Sample translation",
"pagination": "Sample translation",
"...": "..."
}
}
Required fields#
settings.id
Used for the wrapper id comp-{{ id }} and every toggle/panel id (comp-<id>-group-<n>, comp-<id>-list-<key>, comp-<id>-question-<key>).
groups
When empty, nothing is rendered.
Optional fields#
settings.cssClass
Applied only when non-empty and not (UNDEFINED).
settings.header
Rendered as an h2 above the groups; also used as the section aria-label (falls back to translations.faq).
settings.alignment
Center / Right / anything else (left) for the header block.
groups[].title
When empty, the group has no toggle and its lists are always visible.
groups[].faqs[].name
When empty, the list has no toggle and its questions are always visible.
pagination.pageNumber (default 1), pagination.numberOfPages, pagination.pageParameterName (default faqPage)
Pagination renders only when numberOfPages > 1.
Translations used by the template: faq, untitled, pagination, previousPage, nextPage, goToPageNumber, currentPageNumber. noQuestionsSelected and categories are defined in the component translations file.
Template behavior (Liquid + Alpine)#
Keys are built from loop indexes: group <g>, list <g>-<l>, question <g>-<l>-<q>. Merchant text is never interpolated into Alpine expressions.
Initial state is rendered server-side to avoid flicker: every group, list and question starts closed.
Questions with both empty question and answer are skipped. An empty question falls back to translations.untitled.
answer is rendered as HTML.
Every toggle is a button with a bound :aria-expanded and aria-controls pointing to a role="region" panel.
Pagination uses the same sliding-window logic as CustomTable (at most 7 entries, with ... gaps); the current page is a span with aria-current="page".
JavaScript#
Global object#
x-data="faqdefault.initComponent(null, null, null, {{ pageParameterName | serialize | escape }})"
initComponent#
Returns the Alpine state: openKey (question), openGroup (group index), openList (list key) and pageParameterName. A single shared key per level is what makes opening one item close the other.
isOpen#
isOpen(key) returns true when the question key is open.
toggle#
toggle(key) opens the question key, or closes it if it is already open. Opening a question closes any other open question.
isListOpen#
isListOpen(key) returns true when the FAQ list key is open.
toggleList#
toggleList(key) opens or closes a FAQ list.Opening closes every other list, any group other than its own, and any question outside the list.
Its own questions stay closed.
isGroupOpen#
isGroupOpen(index) returns true when the group index is open.
toggleGroup#
toggleGroup(index) opens or closes a group.Opening closes every other group and any list or question outside it.
Its own lists stay closed.
goToPage#
goToPage(page) sets pageParameterName in the query string and performs a full navigation, so every page is server-rendered and linkable.
Notes#
The accordion state is not persisted; a page change resets it to the initial state.
Loading state#
The component is fully server-rendered and has no loading state: its content is shown at first paint.Modified at 2026-10-15 13:48:59