jelonyx
No-app fixes · Fix 03

Shopify FAQ accordion
without an app.

Product FAQs reduce support tickets and objections at the point of purchase. Most stores add a paid app to get them. This fix delivers a smooth, accessible accordion with a single Liquid snippet without an app, monthly fee, or JavaScript library.

DifficultyBeginner
Time~15 minutes
CostFree
Theme accessRequired
Compatible with:Dawn 12+HorizonSenseCraftRefreshMost OS 2.0 themes

The code

One file. Replace the placeholder FAQ text with your own content.

snippets/jlx-faq.liquid
Liquid · CSS · JS
{% comment %}
  Jelonyx · FAQ Accordion : no app required
  Compatible with Dawn 12+, Horizon, and most Online Store 2.0 themes
  Source: jelonyx.com/shopify/no-app/faq-accordion
{% endcomment %}

{%- comment -%}
  Edit the FAQ items below. Copy or delete <details> blocks to add or remove questions.
  Replace the placeholder text with your store's actual content.
{%- endcomment -%}

<div class="jlx-faq" id="jlx-faq">

  <details class="jlx-faq__item">
    <summary class="jlx-faq__q">
      What is your return policy?
      <span class="jlx-faq__icon" aria-hidden="true"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
    </summary>
    <div class="jlx-faq__a"><div class="jlx-faq__a-inner">
      <p>We accept returns within 30 days of purchase. Items must be in their original condition with all original packaging. To start a return, contact us at support@yourstore.com.</p>
    </div></div>
  </details>

  <details class="jlx-faq__item">
    <summary class="jlx-faq__q">
      How long does shipping take?
      <span class="jlx-faq__icon" aria-hidden="true"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
    </summary>
    <div class="jlx-faq__a"><div class="jlx-faq__a-inner">
      <p>Standard shipping takes 5–7 business days. Express shipping (2–3 business days) is available at checkout. Orders placed before 2 pm ship the same day.</p>
    </div></div>
  </details>

  <details class="jlx-faq__item">
    <summary class="jlx-faq__q">
      Do you ship internationally?
      <span class="jlx-faq__icon" aria-hidden="true"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
    </summary>
    <div class="jlx-faq__a"><div class="jlx-faq__a-inner">
      <p>Yes, we ship to most countries. International delivery typically takes 7–14 business days depending on destination. Import duties and taxes may apply and are the responsibility of the buyer.</p>
    </div></div>
  </details>

  <details class="jlx-faq__item">
    <summary class="jlx-faq__q">
      How do I track my order?
      <span class="jlx-faq__icon" aria-hidden="true"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
    </summary>
    <div class="jlx-faq__a"><div class="jlx-faq__a-inner">
      <p>You will receive a tracking link by email once your order ships. You can also view your order status in your account under Order History.</p>
    </div></div>
  </details>

  <details class="jlx-faq__item">
    <summary class="jlx-faq__q">
      Can I change or cancel my order?
      <span class="jlx-faq__icon" aria-hidden="true"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
    </summary>
    <div class="jlx-faq__a"><div class="jlx-faq__a-inner">
      <p>Orders can be changed or cancelled within 2 hours of being placed. After that, fulfilment will have begun. Contact us at support@yourstore.com as soon as possible.</p>
    </div></div>
  </details>

</div>

<style>
  .jlx-faq {
    font-family: inherit;
    border-top: 1px solid var(--color-border, rgba(0, 0, 0, 0.1));
  }
  .jlx-faq__item {
    border-bottom: 1px solid var(--color-border, rgba(0, 0, 0, 0.1));
  }
  .jlx-faq__item summary {
    list-style: none;
  }
  .jlx-faq__item summary::-webkit-details-marker {
    display: none;
  }
  .jlx-faq__q {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 18px 0;
    cursor: pointer;
    font-size: 15px;
    font-weight: 500;
    line-height: 1.4;
    color: var(--color-foreground, #1a1a1a);
    user-select: none;
    transition: opacity 0.15s ease;
  }
  .jlx-faq__q:hover {
    opacity: 0.7;
  }
  .jlx-faq__icon {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    color: var(--color-foreground, #1a1a1a);
    transition: transform 0.25s ease;
  }
  .jlx-faq__item[open]:not(.jlx-is-closing) .jlx-faq__icon {
    transform: rotate(180deg);
  }
  .jlx-faq__a {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.25s ease;
  }
  .jlx-faq__item[open]:not(.jlx-is-closing) .jlx-faq__a {
    grid-template-rows: 1fr;
  }
  .jlx-faq__a-inner {
    overflow: hidden;
  }
  .jlx-faq__a-inner p {
    margin: 0 0 18px;
    font-size: 14px;
    line-height: 1.65;
    color: var(--color-foreground, #1a1a1a);
    opacity: 0.75;
  }
</style>

<script>
  (function () {
    "use strict";
    document.querySelectorAll("#jlx-faq .jlx-faq__item").forEach(function (item) {
      item.addEventListener("click", function (e) {
        var sum = item.querySelector("summary");
        if (!sum.contains(e.target)) return;
        e.preventDefault();
        if (item.open) {
          item.classList.add("jlx-is-closing");
          item.querySelector(".jlx-faq__a").addEventListener(
            "transitionend",
            function () {
              item.open = false;
              item.classList.remove("jlx-is-closing");
            },
            { once: true }
          );
        } else {
          item.open = true;
        }
      });
    });
  })();
</script>

How to install

  1. 01
    Open your theme code editor.

    In Shopify Admin, go to Online Store → Themes. On your active theme, click the three-dot menu and select Edit code.

  2. 02
    Create a new snippet.

    Under the Snippets folder, click Add a new snippet. Name it jlx-faq and click Done.

  3. 03
    Paste the code and edit your FAQ content.

    Delete any placeholder content and paste the entire code block above. Then replace the placeholder question and answer text inside each <details> block with your store's actual FAQs. To add more questions, copy any <details> block and paste it before the closing </div>. Save the file.

  4. 04
    Add the render tag to your product template.

    Open sections/main-product.liquid. Scroll to the bottom of the file and find the line starting with {% schema %}. Add the following on the line directly above it, then save.

    {% render 'jlx-faq' %}

    To add the FAQ to a standalone page instead, open the page in the theme customizer, click Add section → Custom Liquid, and enter the render tag there. No code editing is required.

  5. 05
    Test on a product page.

    Open any product page. The accordion should appear below the product details. Click each question to expand it smoothly and rotate the chevron icon. Click again to collapse.

How it works

The accordion uses the native HTML <details> and <summary> elements, which provide toggle behaviour built into the browser. The open state is tracked by the browser's native open attribute on the <details> element.

The smooth expand and collapse animation uses the CSS grid-template-rows trick: the answer wrapper transitions between 0fr (collapsed, zero height) and 1fr (expanded, natural height). This avoids the imprecise timing of the max-height approach and requires no JavaScript to calculate heights.

The small JavaScript block handles one edge case: the closing animation. Natively, <details> removes the open attribute immediately on click, before any CSS transition can play. The script intercepts the click, adds a jlx-is-closing class to keep the expanded CSS state active, then removes open only after the transition completes via a one-time transitionend listener.

Compatibility

Tested against Dawn 12+ and Horizon. The snippet uses --color-border and --color-foreground CSS variables for borders and text, so it inherits your theme's colour scheme without extra configuration.

The grid-template-rows animation is supported in all browsers used by Shopify storefront visitors (Chrome 57+, Firefox 52+, Safari 10.1+). The <details> element is supported universally.

On themes that define their own styles for <details> or <summary>, you may need to override those theme styles in the snippet CSS. The most common conflict is a theme adding its own details > summary::before marker. Add content: none to .jlx-faq__item summary::before if that appears.

Limitations

  • FAQ content is in code: questions and answers live directly in the snippet file. Editing them requires access to the theme code editor. If you need merchants or non-technical team members to manage FAQ content from the Shopify customizer, that requires a section schema, which is a more involved build.
  • One accordion per page: the snippet uses a fixed id="jlx-faq" for the JavaScript selector. Rendering the snippet more than once on the same page will result in only the first instance having the animated close behaviour. Remove theid and update the JS selector to .jlx-faq if you need multiple instances.
  • Rich text answers: each answer is a plain <p> tag. For answers with links, lists, or formatted text, add the HTML directly inside .jlx-faq__a-inner.
No-App Shopify Fix Sprint

Need this installed?

If you would rather not edit theme code, we can install and style the accordion for your store, populate your actual FAQ content, and set it up so non-technical team members can manage questions from the Shopify customizer.