Pro
← All sections
FAQ + Schema
A searchable, filterable FAQ that answers objections and outputs FAQPage structured data.
Install
One file: sections/mf-faq-schema.liquid. It appears in the theme editor as EX · FAQ + schema.
- Connect EXPERAISE Sections to Claude (once). In Claude Code:In the Claude app: Settings → Connectors → Add custom connector →
claude mcp add --transport http experaise-sections https://sections.experaise.com/api/mcphttps://sections.experaise.com/api/mcp. Full setup - Ask Claude. It fetches
sections/mf-faq-schema.liquid, pushes only that file to your theme with Shopify CLI, and tells you where to find it.Install the EXPERAISE Sections section "FAQ + Schema" (faq-schema) on my Shopify store your-store.myshopify.com. Put it on an unpublished copy of my live theme, then tell me how to add it in the theme editor. - Customize. Online Store → Themes → Customize → Add section → EX · FAQ + schema. Every text, color and product is a setting.
{%- liquid
assign s = section.settings
assign layout = s.layout | default: 'sidebar'
assign total = 0
for block in section.blocks
if block.settings.question != blank
assign total = total | plus: 1
endif
endfor
-%}
{%- capture cats_raw -%}
{%- for block in section.blocks -%}
{%- assign block_cat = block.settings.category | strip -%}
{%- if block_cat != blank and block.settings.question != blank -%}{{ block_cat }}|{%- endif -%}
{%- endfor -%}
{%- endcapture -%}
{%- liquid
assign categories = cats_raw | split: '|' | uniq
assign cat_count = 0
for cat in categories
if cat != blank
assign cat_count = cat_count | plus: 1
endif
endfor
assign show_filters = false
if s.show_filters and cat_count > 1
assign show_filters = true
endif
assign status_text = s.results_template | replace: '[count]', total | replace: '[total]', total
assign contact_url = s.contact_link | default: '/pages/contact'
-%}
{%- capture contact_html -%}
{%- if s.show_contact -%}
<div class="mf-faq__contact">
<div class="mf-faq__contact-top">
<span class="mf-faq__faces" aria-hidden="true"><i></i><i></i><i></i></span>
{%- if s.contact_status != blank -%}
<span class="mf-faq__online"><i aria-hidden="true"></i>{{ s.contact_status | escape }}</span>
{%- endif -%}
</div>
<div class="mf-faq__contact-copy">
{%- if s.contact_heading != blank -%}
<p class="mf-faq__contact-title">{{ s.contact_heading | escape }}</p>
{%- endif -%}
{%- if s.contact_text != blank -%}
<p class="mf-faq__contact-text">{{ s.contact_text | escape }}</p>
{%- endif -%}
</div>
{%- if s.contact_button_label != blank -%}
<a class="mf-faq__contact-btn" href="{{ contact_url }}">
{{- s.contact_button_label | escape -}}
<svg viewBox="0 0 20 20" width="16" height="16" aria-hidden="true"><path d="M4 10h11m-4.5-5 5 5-5 5" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
</a>
{%- endif -%}
</div>
{%- endif -%}
{%- endcapture -%}
<mf-faq-schema
class="mf-faq mf-faq--{{ layout }}{% if s.show_numbers %} mf-faq--numbered{% endif %}"
data-single="{{ s.single_open }}"
data-results="{{ s.results_template | escape }}"
data-total="{{ total }}"
style="--mf-faq-bg: {{ s.color_bg }}; --mf-faq-fg: {{ s.color_text }}; --mf-faq-card: {{ s.color_card }}; --mf-faq-accent: {{ s.color_accent }}; --mf-faq-contact-bg: {{ s.color_contact_bg }}; --mf-faq-contact-fg: {{ s.color_contact_text }}; --mf-faq-pt: {{ s.padding_top }}px; --mf-faq-pb: {{ s.padding_bottom }}px;"
>
<div class="mf-faq__inner">
<div class="mf-faq__aside">
<div class="mf-faq__intro">
{%- if s.eyebrow != blank -%}
<p class="mf-faq__eyebrow">{{ s.eyebrow | escape }}</p>
{%- endif -%}
{%- if s.heading != blank -%}
<h2 class="mf-faq__title">{{ s.heading }}</h2>
{%- endif -%}
{%- if s.text != blank -%}
<div class="mf-faq__text">{{ s.text }}</div>
{%- endif -%}
</div>
{%- if layout == 'sidebar' -%}{{ contact_html }}{%- endif -%}
</div>
<div class="mf-faq__main">
{%- if s.show_search or show_filters -%}
<div class="mf-faq__toolbar" data-mf-toolbar hidden>
{%- if s.show_search -%}
<div class="mf-faq__search">
<label class="mf-faq__sr" for="MfFaqSearch-{{ section.id }}">{{ s.search_placeholder | escape }}</label>
<svg class="mf-faq__search-icon" viewBox="0 0 20 20" width="18" height="18" aria-hidden="true"><circle cx="9" cy="9" r="5.8" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="m13.4 13.4 3.6 3.6" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>
<input
class="mf-faq__search-input"
id="MfFaqSearch-{{ section.id }}"
type="search"
placeholder="{{ s.search_placeholder | escape }}"
autocomplete="off"
spellcheck="false"
aria-controls="MfFaqList-{{ section.id }}"
data-mf-search
>
<button type="button" class="mf-faq__search-clear" aria-label="{{ s.clear_label | escape }}" data-mf-reset hidden>
<svg viewBox="0 0 20 20" width="14" height="14" aria-hidden="true"><path d="m5 5 10 10M15 5 5 15" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
</button>
</div>
{%- endif -%}
<div class="mf-faq__bar">
{%- if show_filters -%}
<div class="mf-faq__filters" role="group" aria-label="{{ s.filter_label | escape }}">
<span class="mf-faq__glider" aria-hidden="true"></span>
<button type="button" class="mf-faq__tab" data-mf-filter="all" aria-pressed="true">
{{- s.all_label | escape -}}
<span class="mf-faq__tab-count" aria-hidden="true">{{ total }}</span>
</button>
{%- for cat in categories -%}
{%- if cat == blank -%}{%- continue -%}{%- endif -%}
{%- assign cat_n = 0 -%}
{%- for block in section.blocks -%}
{%- assign block_cat = block.settings.category | strip -%}
{%- if block_cat == cat and block.settings.question != blank -%}
{%- assign cat_n = cat_n | plus: 1 -%}
{%- endif -%}
{%- endfor -%}
<button type="button" class="mf-faq__tab" data-mf-filter="{{ cat | handleize }}" aria-pressed="false">
{{- cat | escape -}}
<span class="mf-faq__tab-count" aria-hidden="true">{{ cat_n }}</span>
</button>
{%- endfor -%}
</div>
{%- endif -%}
<p class="mf-faq__count" aria-hidden="true" data-mf-count>{{ status_text | escape }}</p>
</div>
<p class="mf-faq__sr" role="status" aria-live="polite" data-mf-status></p>
</div>
{%- endif -%}
<div class="mf-faq__list" id="MfFaqList-{{ section.id }}">
{%- assign n = 0 -%}
{%- for block in section.blocks -%}
{%- if block.settings.question == blank -%}{%- continue -%}{%- endif -%}
{%- liquid
assign n = n | plus: 1
assign block_cat = block.settings.category | strip
-%}
<details
class="mf-faq__item"
id="mf-faq-{{ block.id }}"
data-category="{{ block_cat | handleize }}"
style="--mf-faq-i: {{ n | minus: 1 }};"
{% if s.single_open %}
name="mf-faq-{{ section.id }}"
{% endif %}
{% if s.open_first and n == 1 %}
open
{% endif %}
{{ block.shopify_attributes }}
>
<summary class="mf-faq__summary">
{%- if s.show_numbers -%}
<span class="mf-faq__num" aria-hidden="true">{% if n < 10 %}0{% endif %}{{ n }}</span>
{%- endif -%}
<span class="mf-faq__qwrap">
{%- if block_cat != blank -%}
<span class="mf-faq__kicker" aria-hidden="true">{{ block_cat | escape }}</span>
{%- endif -%}
<span class="mf-faq__q" data-mf-q>{{ block.settings.question | escape }}</span>
</span>
<span class="mf-faq__icon" aria-hidden="true"></span>
</summary>
<div class="mf-faq__a">
<div class="mf-faq__a-inner">{{ block.settings.answer }}</div>
</div>
</details>
{%- endfor -%}
{%- if total == 0 -%}
<div class="mf-faq__empty mf-faq__empty--static">
<p class="mf-faq__empty-title">{{ s.no_results_heading | escape }}</p>
</div>
{%- endif -%}
</div>
<div class="mf-faq__empty" data-mf-empty hidden>
<span class="mf-faq__empty-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" width="22" height="22"><circle cx="11" cy="11" r="6.5" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="m16 16 4 4M8.5 11h5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>
</span>
<p class="mf-faq__empty-title">{{ s.no_results_heading | escape }}</p>
{%- if s.no_results_text != blank -%}
<p class="mf-faq__empty-text">{{ s.no_results_text | escape }}</p>
{%- endif -%}
<button type="button" class="mf-faq__empty-btn" data-mf-reset>{{ s.clear_label | escape }}</button>
</div>
{%- if layout == 'stacked' -%}{{ contact_html }}{%- endif -%}
</div>
</div>
{%- if s.enable_schema and total > 0 -%}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{%- assign sep = '' -%}
{%- for block in section.blocks -%}
{%- if block.settings.question != blank and block.settings.answer != blank -%}
{%- liquid
assign answer_text = block.settings.answer | replace: '</p>', '</p> ' | replace: '<br>', ' ' | replace: '</li>', '</li> ' | strip_html
assign answer_text = answer_text | replace: ' ', ' ' | replace: '"', '"' | replace: ''', "'" | replace: '&', '&' | strip_newlines | strip
assign question_text = block.settings.question | strip_html | strip
-%}
{{ sep }}{
"@type": "Question",
"name": {{ question_text | json }},
"acceptedAnswer": {
"@type": "Answer",
"text": {{ answer_text | json }}
}
}
{%- assign sep = ',' -%}
{%- endif -%}
{%- endfor -%}
]
}
</script>
{%- endif -%}
</mf-faq-schema>
{% stylesheet %}
.mf-faq {
--mf-faq-line: color-mix(in srgb, var(--mf-faq-fg) 11%, transparent);
--mf-faq-line-strong: color-mix(in srgb, var(--mf-faq-fg) 20%, transparent);
--mf-faq-muted: color-mix(in srgb, var(--mf-faq-fg) 70%, var(--mf-faq-bg));
--mf-faq-ease: cubic-bezier(0.2, 0.7, 0.2, 1);
position: relative;
isolation: isolate;
display: block;
padding: var(--mf-faq-pt, 96px) 0 var(--mf-faq-pb, 96px);
background:
radial-gradient(900px 520px at 100% 0%, color-mix(in srgb, var(--mf-faq-accent) 9%, transparent), transparent 70%),
radial-gradient(760px 480px at 0% 100%, color-mix(in srgb, var(--mf-faq-fg) 5%, transparent), transparent 70%),
var(--mf-faq-bg, #f3efe8);
color: var(--mf-faq-fg, #1c1a17);
font-family: inherit;
}
.mf-faq *,
.mf-faq *::before,
.mf-faq *::after {
box-sizing: border-box;
}
.mf-faq [hidden] {
display: none !important;
}
.mf-faq__inner {
display: grid;
grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
align-items: start;
gap: clamp(40px, 6vw, 104px);
width: min(100% - 40px, 1240px);
margin: 0 auto;
}
.mf-faq__aside {
position: sticky;
top: 32px;
display: grid;
gap: 40px;
}
/* Intro ---------------------------------------------------------- */
.mf-faq__eyebrow {
display: flex;
align-items: center;
gap: 12px;
margin: 0 0 22px;
color: var(--mf-faq-accent);
font: 600 11px/1.3 ui-monospace, SFMono-Regular, Menlo, monospace;
letter-spacing: 0.2em;
text-transform: uppercase;
}
.mf-faq__eyebrow::before {
content: "";
width: 28px;
height: 1px;
background: currentColor;
}
.mf-faq__title {
margin: 0;
font-family: inherit;
font-size: clamp(42px, 5.4vw, 78px);
font-weight: 500;
line-height: 0.98;
letter-spacing: -0.045em;
text-transform: none;
color: var(--mf-faq-fg);
text-wrap: balance;
}
.mf-faq__title em {
padding: 0 0.04em;
font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
font-style: italic;
font-weight: 400;
letter-spacing: -0.03em;
color: var(--mf-faq-accent);
background: linear-gradient(color-mix(in srgb, var(--mf-faq-accent) 16%, transparent), color-mix(in srgb, var(--mf-faq-accent) 16%, transparent)) no-repeat 0 86% / 100% 0.16em;
}
.mf-faq__text {
max-width: 42ch;
margin-top: 24px;
color: var(--mf-faq-muted);
font-size: 17px;
line-height: 1.65;
letter-spacing: 0;
}
.mf-faq__text p {
margin: 0;
font-size: inherit;
line-height: inherit;
color: inherit;
}
.mf-faq__text p + p {
margin-top: 12px;
}
.mf-faq__text a {
color: var(--mf-faq-fg);
text-underline-offset: 3px;
}
/* Contact card ---------------------------------------------------- */
.mf-faq__contact {
position: relative;
overflow: hidden;
display: grid;
gap: 18px;
padding: 26px;
border-radius: 24px;
background:
radial-gradient(360px 220px at 100% 0%, color-mix(in srgb, var(--mf-faq-accent) 38%, transparent), transparent 70%),
var(--mf-faq-contact-bg);
color: var(--mf-faq-contact-fg);
box-shadow: 0 30px 60px -36px rgba(20, 14, 8, 0.55);
}
.mf-faq__contact::after {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
border: 1px solid color-mix(in srgb, var(--mf-faq-contact-fg) 12%, transparent);
pointer-events: none;
}
.mf-faq__contact-top {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.mf-faq__faces {
display: flex;
padding-left: 10px;
}
.mf-faq__faces i {
position: relative;
display: block;
width: 36px;
height: 36px;
margin-left: -10px;
border: 2px solid var(--mf-faq-contact-bg);
border-radius: 50%;
background: linear-gradient(145deg, #f4d3bd, #c9764f);
}
.mf-faq__faces i::after {
content: "";
position: absolute;
inset: 16% 30% 46% 24%;
border-radius: 50%;
background: rgba(255, 255, 255, 0.42);
filter: blur(2px);
}
.mf-faq__faces i:nth-child(2) {
background: linear-gradient(145deg, #dfe6d2, #7e9163);
}
.mf-faq__faces i:nth-child(3) {
background: linear-gradient(145deg, #eadcf2, #9a7bb4);
}
.mf-faq__online {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 6px 12px;
border-radius: 999px;
background: color-mix(in srgb, var(--mf-faq-contact-fg) 9%, transparent);
font-size: 12px;
font-weight: 600;
line-height: 1.2;
letter-spacing: 0.01em;
}
.mf-faq__online i {
position: relative;
width: 7px;
height: 7px;
border-radius: 50%;
background: #5fd68a;
}
.mf-faq__online i::after {
content: "";
position: absolute;
inset: 0;
border-radius: 50%;
background: #5fd68a;
animation: mf-faq-ping 2s ease-out infinite;
}
.mf-faq__contact-copy {
display: grid;
gap: 8px;
}
.mf-faq__contact-title {
margin: 0;
color: inherit;
font-size: 22px;
font-weight: 600;
line-height: 1.2;
letter-spacing: -0.02em;
}
.mf-faq__contact-text {
margin: 0;
max-width: 38ch;
color: color-mix(in srgb, var(--mf-faq-contact-fg) 72%, var(--mf-faq-contact-bg));
font-size: 15px;
line-height: 1.55;
letter-spacing: 0;
}
.mf-faq__contact-btn {
display: inline-flex;
align-items: center;
justify-content: center;
justify-self: start;
gap: 10px;
min-height: 48px;
padding: 0 22px;
border-radius: 999px;
background: var(--mf-faq-contact-fg);
color: var(--mf-faq-contact-bg);
font-size: 15px;
font-weight: 600;
line-height: 1;
letter-spacing: 0;
text-decoration: none;
transition: transform 0.25s var(--mf-faq-ease), box-shadow 0.25s ease;
}
.mf-faq__contact-btn svg {
transition: transform 0.25s var(--mf-faq-ease);
}
.mf-faq__contact-btn:hover {
transform: translateY(-2px);
box-shadow: 0 14px 28px -14px rgba(0, 0, 0, 0.6);
}
.mf-faq__contact-btn:hover svg {
transform: translateX(3px);
}
.mf-faq__contact-btn:focus-visible {
outline: 2px solid var(--mf-faq-contact-fg);
outline-offset: 3px;
}
/* Toolbar -------------------------------------------------------- */
.mf-faq__toolbar {
display: grid;
gap: 14px;
margin-bottom: 22px;
}
.mf-faq__search {
position: relative;
display: flex;
align-items: center;
}
.mf-faq__search-icon {
position: absolute;
left: 20px;
color: var(--mf-faq-muted);
pointer-events: none;
}
.mf-faq__search-input {
-webkit-appearance: none;
appearance: none;
width: 100%;
height: 60px;
margin: 0;
padding: 0 56px 0 52px;
border: 1px solid var(--mf-faq-line);
border-radius: 18px;
outline: 0;
background: var(--mf-faq-card);
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.6) inset, 0 12px 30px -24px rgba(40, 28, 12, 0.45);
color: var(--mf-faq-fg);
font-family: inherit;
font-size: 16px;
font-weight: 400;
line-height: 1.2;
letter-spacing: 0;
text-transform: none;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.mf-faq__search-input::placeholder {
color: var(--mf-faq-muted);
opacity: 1;
}
.mf-faq__search-input::-webkit-search-cancel-button,
.mf-faq__search-input::-webkit-search-decoration {
-webkit-appearance: none;
appearance: none;
}
.mf-faq__search-input:hover {
border-color: var(--mf-faq-line-strong);
}
.mf-faq__search-input:focus-visible {
border-color: var(--mf-faq-accent);
box-shadow: 0 0 0 4px color-mix(in srgb, var(--mf-faq-accent) 16%, transparent), 0 12px 30px -24px rgba(40, 28, 12, 0.45);
}
.mf-faq__search-clear {
-webkit-appearance: none;
appearance: none;
position: absolute;
right: 12px;
display: grid;
place-items: center;
width: 36px;
height: 36px;
margin: 0;
padding: 0;
border: 0;
border-radius: 50%;
background: color-mix(in srgb, var(--mf-faq-fg) 7%, transparent);
color: var(--mf-faq-fg);
cursor: pointer;
transition: background 0.2s ease;
}
.mf-faq__search-clear:hover {
background: color-mix(in srgb, var(--mf-faq-fg) 13%, transparent);
}
.mf-faq__search-clear:focus-visible {
outline: 2px solid var(--mf-faq-accent);
outline-offset: 2px;
}
.mf-faq__bar {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 12px 20px;
}
.mf-faq__filters {
position: relative;
display: inline-flex;
gap: 2px;
max-width: 100%;
padding: 4px;
border-radius: 999px;
background: color-mix(in srgb, var(--mf-faq-fg) 6%, transparent);
overflow-x: auto;
scrollbar-width: none;
}
.mf-faq__filters::-webkit-scrollbar {
display: none;
}
.mf-faq__glider {
position: absolute;
top: 4px;
bottom: 4px;
left: 0;
width: 0;
border-radius: 999px;
background: var(--mf-faq-fg);
box-shadow: 0 6px 16px -8px rgba(0, 0, 0, 0.5);
opacity: 0;
}
.mf-faq__glider--ready {
opacity: 1;
transition: transform 0.45s var(--mf-faq-ease), width 0.45s var(--mf-faq-ease);
}
.mf-faq__tab {
-webkit-appearance: none;
appearance: none;
position: relative;
z-index: 1;
display: inline-flex;
flex: none;
align-items: center;
gap: 8px;
min-height: 40px;
margin: 0;
padding: 0 16px;
border: 0;
border-radius: 999px;
background: transparent;
color: var(--mf-faq-muted);
font-family: inherit;
font-size: 14px;
font-weight: 600;
line-height: 1;
letter-spacing: 0;
text-transform: none;
white-space: nowrap;
cursor: pointer;
transition: color 0.3s ease;
}
.mf-faq__tab:hover {
color: var(--mf-faq-fg);
}
.mf-faq__tab[aria-pressed="true"] {
color: var(--mf-faq-bg);
}
.mf-faq__filters:not(:has(.mf-faq__glider--ready)) .mf-faq__tab[aria-pressed="true"] {
background: var(--mf-faq-fg);
}
.mf-faq__tab:focus-visible {
outline: 2px solid var(--mf-faq-accent);
outline-offset: -2px;
}
.mf-faq__tab-count {
display: inline-grid;
place-items: center;
min-width: 20px;
height: 20px;
padding: 0 6px;
border-radius: 999px;
background: color-mix(in srgb, currentColor 14%, transparent);
font: 600 11px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
}
.mf-faq__count {
margin: 0;
color: var(--mf-faq-muted);
font: 500 12px/1.3 ui-monospace, SFMono-Regular, Menlo, monospace;
letter-spacing: 0.04em;
}
/* Accordion ------------------------------------------------------ */
.mf-faq__list {
display: grid;
gap: 10px;
}
.mf-faq__item {
display: block;
margin: 0;
border: 1px solid var(--mf-faq-line);
border-radius: 20px;
background: var(--mf-faq-card);
transition: border-color 0.3s ease, box-shadow 0.4s ease;
}
.mf-faq__item:hover {
border-color: var(--mf-faq-line-strong);
}
.mf-faq__item[open] {
border-color: var(--mf-faq-line-strong);
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.7) inset, 0 26px 50px -34px rgba(40, 28, 12, 0.45);
}
.mf-faq__summary {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
gap: 18px;
padding: 20px 20px 20px 26px;
border-radius: 19px;
color: var(--mf-faq-fg);
list-style: none;
cursor: pointer;
-webkit-user-select: none;
user-select: none;
}
.mf-faq--numbered .mf-faq__summary {
grid-template-columns: 28px minmax(0, 1fr) auto;
}
.mf-faq__summary::-webkit-details-marker {
display: none;
}
.mf-faq__summary::marker {
content: "";
}
.mf-faq__summary:focus-visible {
outline: 2px solid var(--mf-faq-accent);
outline-offset: -3px;
}
.mf-faq__num {
align-self: start;
padding-top: 3px;
color: var(--mf-faq-accent);
font: 600 12px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace;
letter-spacing: 0.04em;
font-variant-numeric: tabular-nums;
}
.mf-faq__qwrap {
display: grid;
gap: 5px;
min-width: 0;
}
.mf-faq__kicker {
color: var(--mf-faq-muted);
font: 600 10.5px/1.3 ui-monospace, SFMono-Regular, Menlo, monospace;
letter-spacing: 0.16em;
text-transform: uppercase;
}
.mf-faq__q {
color: var(--mf-faq-fg);
font-size: clamp(16px, 1.35vw, 19px);
font-weight: 560;
line-height: 1.35;
letter-spacing: -0.012em;
}
.mf-faq__q mark {
padding: 0 2px;
border-radius: 4px;
background: color-mix(in srgb, var(--mf-faq-accent) 22%, transparent);
color: inherit;
}
.mf-faq__icon {
position: relative;
width: 38px;
height: 38px;
border: 1px solid var(--mf-faq-line-strong);
border-radius: 50%;
transition: background 0.35s ease, border-color 0.35s ease, transform 0.45s var(--mf-faq-ease);
}
.mf-faq__icon::before,
.mf-faq__icon::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 12px;
height: 1.6px;
margin: -0.8px 0 0 -6px;
border-radius: 2px;
background: var(--mf-faq-fg);
transition: transform 0.45s var(--mf-faq-ease), background 0.35s ease;
}
.mf-faq__icon::after {
transform: rotate(90deg);
}
.mf-faq__summary:hover .mf-faq__icon {
border-color: var(--mf-faq-fg);
}
.mf-faq__item[open]:not([data-closing]) .mf-faq__icon {
border-color: var(--mf-faq-fg);
background: var(--mf-faq-fg);
transform: rotate(180deg);
}
.mf-faq__item[open]:not([data-closing]) .mf-faq__icon::before,
.mf-faq__item[open]:not([data-closing]) .mf-faq__icon::after {
background: var(--mf-faq-card);
}
.mf-faq__item[open]:not([data-closing]) .mf-faq__icon::after {
transform: rotate(0deg);
}
.mf-faq__a {
padding: 0 26px 26px;
}
.mf-faq--numbered .mf-faq__a {
padding-left: 72px;
}
.mf-faq__item[open] .mf-faq__a-inner {
animation: mf-faq-fade 0.5s var(--mf-faq-ease) both;
}
.mf-faq__a-inner {
max-width: 62ch;
color: var(--mf-faq-muted);
font-size: 16px;
line-height: 1.7;
letter-spacing: 0;
}
.mf-faq__a-inner > * {
margin: 0;
}
.mf-faq__a-inner > * + * {
margin-top: 12px;
}
.mf-faq__a-inner p,
.mf-faq__a-inner li {
font-size: inherit;
line-height: inherit;
color: inherit;
}
.mf-faq__a-inner ul,
.mf-faq__a-inner ol {
padding-left: 20px;
}
.mf-faq__a-inner a {
color: var(--mf-faq-fg);
text-decoration: underline;
text-decoration-color: var(--mf-faq-accent);
text-underline-offset: 3px;
}
.mf-faq__a-inner a:focus-visible {
outline: 2px solid var(--mf-faq-accent);
outline-offset: 2px;
}
.mf-faq__a-inner strong {
color: var(--mf-faq-fg);
font-weight: 600;
}
/* Empty state ---------------------------------------------------- */
.mf-faq__empty {
display: grid;
justify-items: center;
gap: 10px;
padding: 44px 24px;
border: 1px dashed var(--mf-faq-line-strong);
border-radius: 20px;
text-align: center;
animation: mf-faq-fade 0.4s var(--mf-faq-ease) both;
}
.mf-faq__empty-icon {
display: grid;
place-items: center;
width: 52px;
height: 52px;
margin-bottom: 4px;
border-radius: 50%;
background: color-mix(in srgb, var(--mf-faq-accent) 12%, transparent);
color: var(--mf-faq-accent);
}
.mf-faq__empty-title {
margin: 0;
color: var(--mf-faq-fg);
font-size: 18px;
font-weight: 600;
line-height: 1.3;
letter-spacing: -0.01em;
}
.mf-faq__empty-text {
max-width: 40ch;
margin: 0;
color: var(--mf-faq-muted);
font-size: 15px;
line-height: 1.55;
}
.mf-faq__empty-btn {
-webkit-appearance: none;
appearance: none;
min-height: 44px;
margin: 8px 0 0;
padding: 0 20px;
border: 1px solid var(--mf-faq-fg);
border-radius: 999px;
background: transparent;
color: var(--mf-faq-fg);
font-family: inherit;
font-size: 14px;
font-weight: 600;
line-height: 1;
letter-spacing: 0;
text-transform: none;
cursor: pointer;
transition: background 0.2s ease, color 0.2s ease;
}
.mf-faq__empty-btn:hover {
background: var(--mf-faq-fg);
color: var(--mf-faq-bg);
}
.mf-faq__empty-btn:focus-visible {
outline: 2px solid var(--mf-faq-accent);
outline-offset: 3px;
}
/* Stacked layout ------------------------------------------------- */
.mf-faq--stacked .mf-faq__inner {
grid-template-columns: minmax(0, 1fr);
width: min(100% - 40px, 880px);
gap: 48px;
}
.mf-faq--stacked .mf-faq__aside {
position: static;
justify-items: center;
text-align: center;
}
.mf-faq--stacked .mf-faq__eyebrow {
justify-content: center;
}
.mf-faq--stacked .mf-faq__text {
margin-left: auto;
margin-right: auto;
}
.mf-faq--stacked .mf-faq__contact {
grid-template-columns: auto minmax(0, 1fr) auto;
align-items: center;
gap: 22px;
margin-top: 28px;
}
.mf-faq--stacked .mf-faq__contact-top {
display: contents;
}
.mf-faq--stacked .mf-faq__online {
display: none;
}
/* Entrance (JS only) -------------------------------------------- */
.mf-faq--js .mf-faq__intro,
.mf-faq--js .mf-faq__contact,
.mf-faq--js .mf-faq__toolbar,
.mf-faq--js .mf-faq__item {
opacity: 0;
transform: translateY(18px);
transition: opacity 0.6s ease, transform 0.7s var(--mf-faq-ease), border-color 0.3s ease, box-shadow 0.4s ease;
}
.mf-faq--js .mf-faq__contact {
transition-delay: 0.15s;
}
.mf-faq--js .mf-faq__toolbar {
transition-delay: 0.1s;
}
.mf-faq--js .mf-faq__item {
transition-delay: calc(0.18s + var(--mf-faq-i, 0) * 0.05s), calc(0.18s + var(--mf-faq-i, 0) * 0.05s), 0s, 0s;
}
.mf-faq--js .mf-faq__title em {
background-size: 0% 0.16em;
transition: background-size 0.9s var(--mf-faq-ease) 0.45s;
}
.mf-faq--js.mf-faq--in .mf-faq__intro,
.mf-faq--js.mf-faq--in .mf-faq__contact,
.mf-faq--js.mf-faq--in .mf-faq__toolbar,
.mf-faq--js.mf-faq--in .mf-faq__item {
opacity: 1;
transform: none;
}
.mf-faq--js.mf-faq--in .mf-faq__title em {
background-size: 100% 0.16em;
}
.mf-faq__sr {
position: absolute !important;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
border: 0;
}
@keyframes mf-faq-fade {
from { opacity: 0; transform: translateY(-6px); }
to { opacity: 1; transform: none; }
}
@keyframes mf-faq-ping {
0% { opacity: 0.7; transform: scale(1); }
80%, 100% { opacity: 0; transform: scale(2.8); }
}
@media screen and (max-width: 989px) {
.mf-faq__inner {
grid-template-columns: minmax(0, 1fr);
gap: 40px;
}
.mf-faq__aside {
position: static;
}
}
@media screen and (max-width: 749px) {
.mf-faq {
padding-top: min(var(--mf-faq-pt, 96px), 64px);
padding-bottom: min(var(--mf-faq-pb, 96px), 64px);
}
.mf-faq__inner,
.mf-faq--stacked .mf-faq__inner {
display: flex;
flex-direction: column;
gap: 32px;
width: min(100% - 32px, 1240px);
}
.mf-faq__aside {
display: contents;
}
.mf-faq__intro {
order: 1;
}
.mf-faq__main {
order: 2;
}
.mf-faq__contact {
order: 3;
}
.mf-faq__title {
font-size: clamp(38px, 11vw, 52px);
}
.mf-faq__text {
margin-top: 18px;
font-size: 16px;
}
.mf-faq__search-input {
height: 54px;
border-radius: 16px;
}
.mf-faq__bar {
display: grid;
gap: 10px;
}
.mf-faq__filters {
margin: 0 -16px;
max-width: none;
width: calc(100% + 32px);
border-radius: 0;
background: none;
padding: 0 16px;
-webkit-mask-image: linear-gradient(90deg, transparent, #000 16px, #000 calc(100% - 24px), transparent);
mask-image: linear-gradient(90deg, transparent, #000 16px, #000 calc(100% - 24px), transparent);
}
.mf-faq__glider {
top: 0;
bottom: 0;
}
.mf-faq__tab {
border: 1px solid var(--mf-faq-line);
}
.mf-faq__tab[aria-pressed="true"] {
border-color: transparent;
}
.mf-faq__summary {
gap: 12px;
padding: 18px 16px 18px 18px;
}
.mf-faq--numbered .mf-faq__summary {
grid-template-columns: 22px minmax(0, 1fr) auto;
}
.mf-faq__q {
font-size: 16px;
}
.mf-faq__icon {
width: 34px;
height: 34px;
}
.mf-faq__a,
.mf-faq--numbered .mf-faq__a {
padding: 0 18px 22px;
}
.mf-faq--numbered .mf-faq__a {
padding-left: 52px;
}
.mf-faq__a-inner {
font-size: 15px;
}
.mf-faq__contact,
.mf-faq--stacked .mf-faq__contact {
grid-template-columns: minmax(0, 1fr);
margin-top: 0;
padding: 22px;
}
.mf-faq--stacked .mf-faq__contact {
margin-top: 24px;
}
.mf-faq--stacked .mf-faq__contact-top {
display: flex;
}
.mf-faq--stacked .mf-faq__online {
display: inline-flex;
}
.mf-faq__contact-btn {
width: 100%;
}
}
@media (prefers-reduced-motion: reduce) {
.mf-faq__online i::after,
.mf-faq__item[open] .mf-faq__a-inner,
.mf-faq__empty {
animation: none;
}
.mf-faq__glider--ready,
.mf-faq__icon,
.mf-faq__icon::before,
.mf-faq__icon::after,
.mf-faq__contact-btn,
.mf-faq__contact-btn svg {
transition: none;
}
.mf-faq__item[open]:not([data-closing]) .mf-faq__icon {
transform: none;
}
.mf-faq__contact-btn:hover,
.mf-faq__contact-btn:hover svg {
transform: none;
}
.mf-faq--js .mf-faq__intro,
.mf-faq--js .mf-faq__contact,
.mf-faq--js .mf-faq__toolbar,
.mf-faq--js .mf-faq__item {
opacity: 1;
transform: none;
transition: none;
}
.mf-faq--js .mf-faq__title em {
background-size: 100% 0.16em;
transition: none;
}
}
{% endstylesheet %}
{% javascript %}
if (!customElements.get('mf-faq-schema')) {
customElements.define(
'mf-faq-schema',
class extends HTMLElement {
connectedCallback() {
this.reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
this.single = this.dataset.single === 'true';
this.total = Number(this.dataset.total) || 0;
this.items = Array.from(this.querySelectorAll('.mf-faq__item'));
this.search = this.querySelector('[data-mf-search]');
this.clearButton = this.querySelector('.mf-faq__search-clear');
this.tabs = Array.from(this.querySelectorAll('[data-mf-filter]'));
this.glider = this.querySelector('.mf-faq__glider');
this.count = this.querySelector('[data-mf-count]');
this.status = this.querySelector('[data-mf-status]');
this.empty = this.querySelector('[data-mf-empty]');
this.filter = 'all';
this.query = '';
this.running = new Map();
this.items.forEach((item) => {
// JS takes over the one-open-at-a-time behaviour so closing can animate.
item.removeAttribute('name');
const q = item.querySelector('[data-mf-q]');
item.mfQuestion = q ? q.textContent : '';
item.mfHaystack = this.normalize(item.textContent);
});
this.onClick = this.onClick.bind(this);
this.onInput = this.onInput.bind(this);
this.onResize = this.placeGlider.bind(this);
this.onBlockSelect = this.onBlockSelect.bind(this);
this.addEventListener('click', this.onClick);
if (this.search) this.search.addEventListener('input', this.onInput);
window.addEventListener('resize', this.onResize);
document.addEventListener('shopify:block:select', this.onBlockSelect);
this.onHashChange = () => this.openFromHash(true);
window.addEventListener('hashchange', this.onHashChange);
const toolbar = this.querySelector('[data-mf-toolbar]');
if (toolbar) toolbar.hidden = false;
this.placeGlider();
if (this.glider) {
requestAnimationFrame(() => this.glider.classList.add('mf-faq__glider--ready'));
}
this.openFromHash(false);
if (!this.reduce && 'IntersectionObserver' in window) {
this.classList.add('mf-faq--js');
this.observer = new IntersectionObserver(
(entries) => {
if (entries.some((entry) => entry.isIntersecting)) {
this.classList.add('mf-faq--in');
this.observer.disconnect();
}
},
{ rootMargin: '0px 0px -8% 0px' }
);
this.observer.observe(this);
}
}
disconnectedCallback() {
this.removeEventListener('click', this.onClick);
if (this.search) this.search.removeEventListener('input', this.onInput);
window.removeEventListener('resize', this.onResize);
document.removeEventListener('shopify:block:select', this.onBlockSelect);
window.removeEventListener('hashchange', this.onHashChange);
if (this.observer) this.observer.disconnect();
clearTimeout(this.announceTimer);
this.running.forEach((animation) => animation.cancel());
}
openFromHash(animated) {
if (window.location.hash.length < 2) return;
let target = null;
try {
target = document.getElementById(decodeURIComponent(window.location.hash.slice(1)));
} catch (error) {
target = null;
}
if (!target || !this.contains(target) || !target.classList.contains('mf-faq__item')) return;
if (target.hidden) {
this.filter = 'all';
this.query = '';
if (this.search) this.search.value = '';
this.syncTabs();
this.apply();
}
if (animated) {
this.toggle(target, true);
return;
}
if (this.single) {
this.items.forEach((item) => {
if (item !== target) item.open = false;
});
}
target.open = true;
}
normalize(value) {
return String(value || '')
.toLowerCase()
.normalize('NFD')
.replace(/[̀-ͯ]/g, '')
.replace(/\s+/g, ' ');
}
onClick(event) {
const summary = event.target.closest('.mf-faq__summary');
if (summary && this.contains(summary)) {
event.preventDefault();
const item = summary.parentElement;
this.toggle(item, !item.open || item.hasAttribute('data-closing'));
return;
}
const tab = event.target.closest('[data-mf-filter]');
if (tab && this.contains(tab)) {
this.setFilter(tab.dataset.mfFilter);
tab.scrollIntoView({ block: 'nearest', inline: 'nearest', behavior: this.reduce ? 'auto' : 'smooth' });
return;
}
const reset = event.target.closest('[data-mf-reset]');
if (reset && this.contains(reset)) {
if (this.search) this.search.value = '';
this.query = '';
if (reset.classList.contains('mf-faq__empty-btn')) this.filter = 'all';
this.syncTabs();
this.apply();
if (this.search) this.search.focus();
}
}
onInput() {
this.query = this.search.value;
this.apply();
}
onBlockSelect(event) {
const item = event.target && event.target.closest ? event.target.closest('.mf-faq__item') : null;
if (!item || !this.contains(item)) return;
if (item.hidden) {
this.filter = 'all';
this.query = '';
if (this.search) this.search.value = '';
this.syncTabs();
this.apply();
}
this.toggle(item, true);
}
setFilter(value) {
this.filter = value || 'all';
this.syncTabs();
this.apply();
}
syncTabs() {
this.tabs.forEach((tab) => {
tab.setAttribute('aria-pressed', tab.dataset.mfFilter === this.filter ? 'true' : 'false');
});
this.placeGlider();
}
placeGlider() {
if (!this.glider) return;
const active = this.tabs.find((tab) => tab.getAttribute('aria-pressed') === 'true');
if (!active) return;
this.glider.style.width = active.offsetWidth + 'px';
this.glider.style.transform = 'translateX(' + active.offsetLeft + 'px)';
}
apply() {
const query = this.normalize(this.query.trim());
let shown = 0;
this.items.forEach((item) => {
const inCategory = this.filter === 'all' || item.dataset.category === this.filter;
const matches = !query || item.mfHaystack.indexOf(query) !== -1;
const visible = inCategory && matches;
if (visible && item.hidden) {
item.hidden = false;
if (!this.reduce && item.animate) {
item.animate(
[
{ opacity: 0, transform: 'translateY(10px)' },
{ opacity: 1, transform: 'none' },
],
{ duration: 360, easing: 'cubic-bezier(0.2, 0.7, 0.2, 1)' }
);
}
} else if (!visible) {
item.hidden = true;
}
if (visible) shown += 1;
this.highlight(item, visible ? this.query.trim() : '');
});
if (this.empty) this.empty.hidden = shown > 0;
if (this.clearButton) this.clearButton.hidden = !this.query;
const text = (this.dataset.results || '')
.replace('[count]', shown)
.replace('[total]', this.total);
if (this.count) this.count.textContent = text;
clearTimeout(this.announceTimer);
this.announceTimer = setTimeout(() => {
if (this.status) this.status.textContent = text;
}, 450);
}
highlight(item, raw) {
const node = item.querySelector('[data-mf-q]');
if (!node) return;
const original = item.mfQuestion;
const index = raw ? original.toLowerCase().indexOf(raw.toLowerCase()) : -1;
if (index === -1) {
if (node.childElementCount || node.textContent !== original) node.textContent = original;
return;
}
const mark = document.createElement('mark');
mark.textContent = original.slice(index, index + raw.length);
node.replaceChildren(
document.createTextNode(original.slice(0, index)),
mark,
document.createTextNode(original.slice(index + raw.length))
);
}
toggle(item, open) {
if (open && this.single) {
this.items.forEach((other) => {
if (other !== item && other.open && !other.hasAttribute('data-closing')) this.animate(other, false);
});
}
this.animate(item, open);
}
animate(item, open) {
const summary = item.querySelector('.mf-faq__summary');
const previous = this.running.get(item);
if (this.reduce || document.hidden || !item.animate || !summary) {
if (previous) previous.cancel();
item.removeAttribute('data-closing');
item.open = open;
return;
}
const start = item.offsetHeight;
if (previous) {
this.running.delete(item);
previous.cancel();
}
item.style.overflow = 'hidden';
item.open = true;
if (open) item.removeAttribute('data-closing');
else item.setAttribute('data-closing', '');
const border = item.offsetHeight - item.clientHeight;
const end = open ? item.offsetHeight : summary.offsetHeight + border;
const animation = item.animate(
{ height: [start + 'px', end + 'px'] },
{ duration: open ? 460 : 360, easing: 'cubic-bezier(0.2, 0.7, 0.2, 1)' }
);
this.running.set(item, animation);
animation.onfinish = () => {
if (this.running.get(item) !== animation) return;
this.running.delete(item);
item.open = open;
item.removeAttribute('data-closing');
item.style.overflow = '';
};
}
}
);
}
{% endjavascript %}
{% schema %}
{
"name": "EX · FAQ + schema",
"tag": "section",
"class": "mf-section",
"disabled_on": {
"groups": ["header", "footer"]
},
"max_blocks": 50,
"settings": [
{
"type": "header",
"content": "Content"
},
{
"type": "text",
"id": "eyebrow",
"label": "Eyebrow",
"default": "Help centre"
},
{
"type": "inline_richtext",
"id": "heading",
"label": "Heading",
"info": "Wrap words in italics for the serif accent.",
"default": "Questions, <em>answered.</em>"
},
{
"type": "richtext",
"id": "text",
"label": "Text",
"default": "<p>Everything about delivery, formulas and returns in one place. Can’t find what you need? Our skin advisors are one message away.</p>"
},
{
"type": "select",
"id": "layout",
"label": "Layout",
"options": [
{ "value": "sidebar", "label": "Intro beside questions" },
{ "value": "stacked", "label": "Intro above questions" }
],
"default": "sidebar"
},
{
"type": "header",
"content": "Search and filters"
},
{
"type": "checkbox",
"id": "show_search",
"label": "Show search",
"default": true
},
{
"type": "text",
"id": "search_placeholder",
"label": "Search placeholder",
"default": "Search questions"
},
{
"type": "checkbox",
"id": "show_filters",
"label": "Show category tabs",
"info": "Tabs are built from each question's category. They appear when at least two categories exist.",
"default": true
},
{
"type": "text",
"id": "all_label",
"label": "All tab label",
"default": "All"
},
{
"type": "text",
"id": "filter_label",
"label": "Tabs label for screen readers",
"default": "Filter questions by topic"
},
{
"type": "text",
"id": "results_template",
"label": "Results count",
"info": "[count] and [total] are replaced with numbers.",
"default": "[count] of [total] questions"
},
{
"type": "text",
"id": "no_results_heading",
"label": "No results heading",
"default": "No answers match your search"
},
{
"type": "text",
"id": "no_results_text",
"label": "No results text",
"default": "Try a simpler word, or ask our advisors. They reply within two hours."
},
{
"type": "text",
"id": "clear_label",
"label": "Clear search label",
"default": "Clear search"
},
{
"type": "header",
"content": "Accordion"
},
{
"type": "checkbox",
"id": "open_first",
"label": "Open the first question",
"default": true
},
{
"type": "checkbox",
"id": "single_open",
"label": "Close other answers when one opens",
"default": true
},
{
"type": "checkbox",
"id": "show_numbers",
"label": "Show question numbers",
"default": true
},
{
"type": "header",
"content": "Contact card"
},
{
"type": "checkbox",
"id": "show_contact",
"label": "Show contact card",
"default": true
},
{
"type": "text",
"id": "contact_status",
"label": "Status label",
"default": "Advisors online"
},
{
"type": "text",
"id": "contact_heading",
"label": "Heading",
"default": "Still have a question?"
},
{
"type": "text",
"id": "contact_text",
"label": "Text",
"default": "Real people with real skin expertise. We reply within two hours, seven days a week."
},
{
"type": "text",
"id": "contact_button_label",
"label": "Button label",
"default": "Ask an advisor"
},
{
"type": "url",
"id": "contact_link",
"label": "Button link",
"info": "Defaults to /pages/contact."
},
{
"type": "header",
"content": "Search engines"
},
{
"type": "checkbox",
"id": "enable_schema",
"label": "Add FAQ structured data",
"info": "Outputs FAQPage JSON-LD for search engines and AI assistants. Turn off if another section on this page already outputs FAQ structured data.",
"default": true
},
{
"type": "header",
"content": "Spacing"
},
{
"type": "range",
"id": "padding_top",
"label": "Top padding",
"min": 0,
"max": 160,
"step": 8,
"unit": "px",
"default": 96
},
{
"type": "range",
"id": "padding_bottom",
"label": "Bottom padding",
"min": 0,
"max": 160,
"step": 8,
"unit": "px",
"default": 96
},
{
"type": "header",
"content": "Colors"
},
{
"type": "color",
"id": "color_bg",
"label": "Background",
"default": "#f3efe8"
},
{
"type": "color",
"id": "color_text",
"label": "Text",
"default": "#1c1a17"
},
{
"type": "color",
"id": "color_card",
"label": "Question cards",
"default": "#fcfaf6"
},
{
"type": "color",
"id": "color_accent",
"label": "Accent",
"default": "#9b4a2c"
},
{
"type": "color",
"id": "color_contact_bg",
"label": "Contact card background",
"default": "#1f1c19"
},
{
"type": "color",
"id": "color_contact_text",
"label": "Contact card text",
"default": "#f6f1e8"
}
],
"blocks": [
{
"type": "question",
"name": "Question",
"settings": [
{
"type": "text",
"id": "question",
"label": "Question",
"default": "How long does delivery take?"
},
{
"type": "richtext",
"id": "answer",
"label": "Answer",
"default": "<p>Write a clear, complete answer. Shoppers and search engines read it as is.</p>"
},
{
"type": "text",
"id": "category",
"label": "Category",
"info": "Questions with the same category share a filter tab, e.g. Shipping."
}
]
}
],
"presets": [
{
"name": "EX · FAQ + schema",
"blocks": [
{
"type": "question",
"settings": {
"category": "Shipping",
"question": "How long does delivery take?",
"answer": "<p>Orders placed before 2 pm ship the same working day. Standard delivery takes 2–4 working days and is free over €50; express arrives the next working day in most areas. You’ll receive a tracking link as soon as your parcel leaves our studio.</p>"
}
},
{
"type": "question",
"settings": {
"category": "Shipping",
"question": "Do you ship internationally?",
"answer": "<p>Yes, we ship to more than 30 countries. Duties and taxes are calculated at checkout, so there are no surprise fees on delivery. International orders usually arrive in 4–8 working days.</p>"
}
},
{
"type": "question",
"settings": {
"category": "Product",
"question": "Are your formulas suitable for sensitive skin?",
"answer": "<p>Every formula is dermatologist-tested and free from added fragrance, drying alcohols and essential oils. If your skin reacts easily, patch-test on your inner arm for 24 hours before the first full application.</p>"
}
},
{
"type": "question",
"settings": {
"category": "Product",
"question": "Can I use the Hydra Glow Serum with retinol or acids?",
"answer": "<p>Yes. Apply the serum first on clean skin, then your treatment. If you use a strong retinoid, alternate evenings for the first two weeks while your skin adjusts, and always finish with SPF in the morning.</p>"
}
},
{
"type": "question",
"settings": {
"category": "Product",
"question": "Are your products vegan and cruelty-free?",
"answer": "<p>All of our products are vegan and never tested on animals, at any stage. Bottles and jars are glass or recycled aluminium, and refill pouches use 70% less plastic than a new bottle.</p>"
}
},
{
"type": "question",
"settings": {
"category": "Returns",
"question": "What if a product doesn’t suit me?",
"answer": "<p>Try it for 30 days. If it isn’t right for your skin, send it back, even opened, for a full refund. Start a return from your account or reply to your order confirmation email.</p>"
}
},
{
"type": "question",
"settings": {
"category": "Returns",
"question": "When will I receive my refund?",
"answer": "<p>We refund your original payment method as soon as your return reaches us, usually within 3 working days of you sending it. Your bank may take another 2–5 days to show the amount.</p>"
}
}
]
}
]
}
{% endschema %}
Why it converts
Answering delivery, product and return objections on the page removes the doubts that stall checkout, without a support ticket.
Specs
About this section
FAQ + Schema is a free Shopify Online Store 2.0 section for product, collection, home and help pages. Each question is a block with a question, a rich-text answer and a category; the preset ships seven ecommerce questions across Shipping, Product and Returns. Questions render as native details and summary elements, so they open and close with a keyboard and without JavaScript. With JavaScript, answers open with a smooth height animation, other answers can close automatically, a live search filters questions and answers as the shopper types (accent-insensitive, with the match highlighted), and category tabs built from the block categories filter the list with a sliding indicator. A results count updates and is announced to screen readers, and a designed empty state offers to clear the search. A sticky intro column carries an eyebrow, a large heading with an italic serif accent, text and a dark contact card with an online-status pill and a button to your contact page; an alternative layout stacks the intro above the questions. When the structured-data setting is on, the section outputs FAQPage JSON-LD built from the same questions and plain-text answers, so search engines and AI assistants can read them. The conversion principle is objection handling: shoppers who get an answer on the page keep moving toward checkout. Merchants control every label, the layout, numbering, padding and six colors. Reduced-motion preferences disable all animation. It is one self-contained Liquid file with scoped CSS and a small custom element.
Questions
How do the category tabs work?
Give each question block a category in the theme editor, for example Shipping or Returns. The section collects the unique categories and builds one tab per category plus an All tab, each with a count. Tabs only appear when at least two categories exist, and you can switch them off.
What structured data does it output?
A single FAQPage JSON-LD script listing every question with a non-empty answer, using the question text and the answer converted to plain text. Keep one FAQ structured-data source per page: turn the setting off if your theme or an app already adds FAQPage markup. Google shows FAQ rich results only for some sites, but the markup still describes the content to search engines and AI assistants.
Does the FAQ work without JavaScript?
Yes. Questions use native details and summary elements, so they open and close with a click or the keyboard. Search, tabs and the height animation are progressive enhancements: the search and tab toolbar is only shown once the script has loaded.
Can shoppers link straight to one answer?
Yes. Every question has a stable id (mf-faq- followed by the block id). Opening the page with that id as the URL hash opens the matching answer, which is useful in emails and support replies.
More sections
Pro