FreeFeaturedFAQ

FAQ Accordion

Accessible accordion with auto-generated FAQPage schema.

#faq#accordion#schema#seo#accessibility

Live preview

See it in action.

Fully interactive, drag, click, scroll inside the frame, toggle to mobile.

About this section

A spec-compliant disclosure accordion using native <details>/<summary>. Auto-emits FAQPage JSON-LD for rich-result eligibility on Google. Block-driven content.

Install in 90 seconds

  1. 01

    Create /sections/modblo-faq-accordion.liquid.

  2. 02

    Paste the code and save.

  3. 03

    Add the section, then add Question blocks.

The code

This is the file you'll paste into your theme.

modblo-faq-accordion.liquid
{%- comment -%} modblo. FAQ Accordion (with FAQPage schema) {%- endcomment -%}
<section class="modblo-faq" data-section-id="{{ section.id }}"
  style="--modblo-bg: {{ section.settings.bg }}; --modblo-fg: {{ section.settings.fg }};">
  <div class="modblo-faq__inner page-width">
    {%- if section.settings.eyebrow != blank -%}
      <p class="modblo-faq__eyebrow">{{ section.settings.eyebrow }}</p>
    {%- endif -%}
    {%- if section.settings.heading != blank -%}
      <h2 class="modblo-faq__heading">{{ section.settings.heading }}</h2>
    {%- endif -%}

    <div class="modblo-faq__list">
      {%- for block in section.blocks -%}
        <details class="modblo-faq__item" {{ block.shopify_attributes }} {% if forloop.first and section.settings.open_first %}open{% endif %}>
          <summary>
            <span>{{ block.settings.question }}</span>
            <svg viewBox="0 0 16 16" width="16" height="16" aria-hidden="true">
              <path d="M4 6l4 4 4-4" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
            </svg>
          </summary>
          <div class="modblo-faq__answer">{{ block.settings.answer }}</div>
        </details>
      {%- endfor -%}
    </div>
  </div>
</section>

{%- comment -%} FAQPage JSON-LD for SEO {%- endcomment -%}
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {%- for block in section.blocks -%}
      {
        "@type": "Question",
        "name": {{ block.settings.question | json }},
        "acceptedAnswer": {
          "@type": "Answer",
          "text": {{ block.settings.answer | strip_html | json }}
        }
      }{% unless forloop.last %},{% endunless %}
    {%- endfor -%}
  ]
}
</script>

<style>
  .modblo-faq { background: var(--modblo-bg, #fff); color: var(--modblo-fg, #0b0b0c); padding: clamp(64px,10vw,128px) 0; }
  .modblo-faq__inner { max-width: 800px; margin: 0 auto; padding: 0 24px; }
  .modblo-faq__eyebrow { text-transform: uppercase; letter-spacing: .18em; font-size: 12px; opacity: .65; font-weight: 600; margin: 0 0 12px; }
  .modblo-faq__heading { font-size: clamp(28px,4vw,44px); letter-spacing: -.025em; margin: 0 0 32px; }
  .modblo-faq__list { display: grid; gap: 12px; }
  .modblo-faq__item {
    background: color-mix(in oklab, var(--modblo-fg) 3%, transparent);
    border: 1px solid color-mix(in oklab, var(--modblo-fg) 8%, transparent);
    border-radius: 14px; padding: 0 20px;
    transition: background .2s ease, border-color .2s ease;
  }
  .modblo-faq__item[open] {
    background: color-mix(in oklab, var(--modblo-fg) 5%, transparent);
    border-color: color-mix(in oklab, var(--modblo-fg) 14%, transparent);
  }
  .modblo-faq__item summary {
    list-style: none; cursor: pointer;
    display: flex; align-items: center; justify-content: space-between; gap: 16px;
    padding: 18px 0; font-weight: 600; font-size: 16px;
  }
  .modblo-faq__item summary::-webkit-details-marker { display: none; }
  .modblo-faq__item svg { transition: transform .25s cubic-bezier(.16,1,.3,1); flex: none; }
  .modblo-faq__item[open] svg { transform: rotate(180deg); }
  .modblo-faq__answer {
    padding: 0 0 18px;
    font-size: 15px; line-height: 1.6; opacity: .82;
  }
</style>

{% schema %}
{
  "name": "FAQ Accordion",
  "tag": "section",
  "settings": [
    { "type": "text", "id": "eyebrow", "label": "Eyebrow", "default": "FAQ" },
    { "type": "text", "id": "heading", "label": "Heading", "default": "Questions, answered." },
    { "type": "checkbox", "id": "open_first", "label": "Open first item by default", "default": true },
    { "type": "color", "id": "bg", "label": "Background", "default": "#ffffff" },
    { "type": "color", "id": "fg", "label": "Foreground", "default": "#0b0b0c" }
  ],
  "blocks": [{
    "type": "qa",
    "name": "Question",
    "settings": [
      { "type": "text", "id": "question", "label": "Question", "default": "How does shipping work?" },
      { "type": "richtext", "id": "answer", "label": "Answer",
        "default": "<p>Free standard shipping on orders over $75. Express options at checkout.</p>" }
    ]
  }],
  "max_blocks": 24,
  "presets": [{
    "name": "FAQ Accordion",
    "blocks": [{ "type": "qa" }, { "type": "qa" }, { "type": "qa" }]
  }]
}
{% endschema %}

What you can customize

Every setting below shows up in the Shopify theme editor. Change them without touching code.

SettingTypeDefault

Eyebrow

eyebrow

TextFAQ

Heading

heading

TextQuestions, answered.

Open first item

open_first

Yes/Notrue

Background

bg

Color picker#ffffff

Foreground

fg

Color picker#0b0b0c

SEO and accessibility notes

  • Emits valid schema.org FAQPage JSON-LD, eligible for rich results.
  • Uses native <details>/<summary>, keyboard and screen-reader accessible by default.
  • Strip-html'd answer text in JSON-LD prevents schema validation errors.