FAQ Section on collection page

Topic summary

A user is attempting to add an FAQ section to a Shopify collection page but encountering multiple errors.

Initial Problem:

  • Used {% include 'faq' %} syntax, which is incorrect for sections
  • The code appears to contain reversed/obfuscated JavaScript and Liquid template code

Attempted Solutions:

  • First suggestion: Use {% section 'faq' %} instead of {% include 'faq' %} for files in the Sections folder
  • Alternative recommendation: Check if the theme has built-in collapsible content functionality in the theme customizer

Ongoing Issues:

  • “Cannot render sections inside sections” error when trying to include a section within another section (collection-template)
  • Second approach suggested converting the FAQ section into a snippet, then using {% include 'faq' %} to call it
  • Latest error: “Unknown tag ‘schema’” syntax error on line 161

Current Status:
The issue remains unresolved. The user has not received a working solution, and the discussion appears to have stalled without further responses.

Summarized with AI on November 4. AI used: claude-sonnet-4-5-20250929.

Tried to add an FAQ section to our collection using the following code:

Sections/faq.liquid

{%- comment -%}
Section published at https://sections.design/blogs/shopify/faq-rich-snippets-section
Get the latest version: https://github.com/mirceapiturca/Sections/tree/master/FAQ
{%- endcomment -%}

{%- comment -%} ---------------- THE CSS ---------------- {%- endcomment -%}

{%- assign id = '#shopify-section-' | append: section.id -%}

{% style %}
  {{ id }} {
    background: {{ section.settings.background_color }};
    --panel-bg: {{ section.settings.panel_color }};
    --border-color: {{ section.settings.border_color }}; 
    --question-color: {{ section.settings.q_color }};
    --answer-color: {{ section.settings.a_color }};

    {%- assign min = section.settings.q_size_small -%}
    {%- assign max = section.settings.q_size_large -%}
    {%- assign min_rem = min | append: 'rem' -%}
    {%- assign max_rem = max | append: 'rem' -%}
    --title-font-size: clamp({{ min_rem }}, calc({{ min_rem }} + ({{ max }} - {{ min }}) * ((100vw - 25rem) / (64 - 25))), {{ max_rem }});
  }
{% endstyle %}

{%- comment -%} ---------------- THE MARKUP ---------------- {%- endcomment -%}

{%- for block in section.blocks -%}
  {%- if block.settings.title != blank and block.settings.content != blank  -%}
  
    {%- if block.settings.checkbox_expanded == true -%}
      {%- assign expanded = 'true' -%}
      {%- assign hidden = '' -%}
    {%- else -%}
      {%- assign expanded = 'false' -%}
      {%- assign hidden = 'hidden' -%}
    {%- endif -%}
  
    ## 
      
    
  
    
      
{{ block.settings.content }}

    

  
  {%- endif -%}
{%- endfor -%}

{%- comment -%} -------------- THE RICH SCHEMA ------------- {%- endcomment -%}

{%- if section.settings.enable_rich_schema -%}

{%- endif -%}

{%- comment -%} ---------------- THE CONFIG ---------------- {%- endcomment -%}

{%- comment -%} ---------------- THE SETTINGS ---------------- {%- endcomment -%}

{% schema %}
{
  "name": "FAQ",
  "class": "sd-faq",
  "tag": "article",

  "settings": [
    {
      "type": "header",
      "content": "Rich schema"
    },
    {
      "type": "checkbox",
      "id": "enable_rich_schema",
      "default": true,
      "label": "Enable FAQ rich schema?"
    },
    {
      "type": "header",
      "content": "Dimensions"
    },
    {
      "type": "text",
      "id": "max_width",
      "label": "Max width",
      "default": "64rem"
    },
    {
      "type": "range",
      "id": "margin_top",
      "min": 0,
      "max": 10,
      "step": 0.1,
      "unit": "rem",
      "label": "Margin top",
      "default": 1
    },
    {
      "type": "range",
      "id": "margin_bottom",
      "min": 0,
      "max": 10,
      "step": 0.1,
      "unit": "rem",
      "label": "Margin bottom",
      "default": 1
    },
    {
      "type": "header",
      "content": "Colors"
    },
    {
      "type": "color",
      "id": "background_color",
      "label": "Background color",
      "default": "#ffffff"
    },
    {
      "type": "color",
      "id": "border_color",
      "label": "Border color",
      "default": "#eeeeee"
    },
    {
      "type": "color",
      "id": "panel_color",
      "label": "Panel color",
      "default": "#fdfdfd"
    },
    {
      "type": "header",
      "content": "Question"
    },
    {
      "type": "range",
      "id": "q_size_small",
      "min": 1,
      "max": 2,
      "step": 0.1,
      "unit": "rem",
      "label": "Small devices font size",
      "default": 1
    },
    {
      "type": "range",
      "id": "q_size_large",
      "min": 1,
      "max": 3,
      "step": 0.1,
      "unit": "rem",
      "label": "Large devices font size",
      "default": 1.4
    },
    {
      "type": "color",
      "id": "q_color",
      "label": "Question text color"
    },
    {
      "type": "header",
      "content": "Answer"
    },
    {
      "type": "color",
      "id": "a_color",
      "label": "Answer text color"
    }
  ],

  "blocks": [
    {
      "type": "faq",
      "name": "FAQ",
      "settings": [
        {
          "type": "checkbox",
          "id": "checkbox_expanded",
          "default": false,
          "label": "Expanded?"
        },
        {
          "type": "text",
          "id": "title",
          "label": "FAQ title",
          "default": "FAQ title"
        },
        {
          "type": "richtext",
          "id": "content",
          "label": "FAQ content",
          "default": "

FAQ content

"
        }
      ]
    }
  ],

  "presets": [
    {
      "name": "FAQ"
    }
  ]
}
{% endschema %}

{%- comment -%} ------------------ THE JS ----------------- {%- endcomment -%}

{%- comment -%} ---------------- THE NO-JS ---------------- {%- endcomment -%}

{%- comment -%} ---------------- THE EDITOR ------------------ {%- endcomment -%}

{%- if request.design_mode -%}

{%- endif -%}

assets/faq.js

(function FAQ(SectionsDesign) {
  'use strict';
  
  if (SectionsDesign.faq) return;
  SectionsDesign.faq = {};
  
  var support = getSupport();
 
  var init = function() {
    var configNodes = Array.from(document.querySelectorAll('[data-faq-config]'));
    
    configNodes.map(configNode => {
      var section = compose(publicAPI, setEvents, getBlocks, getConfig)(configNode);
      SectionsDesign.faq[section.id] = section;
    });
  }
  
  init();
 
  function publicAPI(config) {
    return {
      id: config.sectionId,
      config: config,
      blocks: zipObj(config.blockIds, config.blocks),
      init: init
    }
  }

  //**************************

  /**
   * Click event.
   * @param {Object} block Section block elements and methods.
   *  {Object} Section block elements and methods.
   */
  function blockEvents(block) {
    if (block.trigger.hasAttribute('data-faq-init')) return block;
    
    block.trigger.setAttribute('data-faq-init', true);
    block.trigger.addEventListener('click', triggerClick);
                                   
    function triggerClick() {
      toggle(block);
    }

    return block;
  }

  /**
   * Toggle block state.
   * @param {Object} block Section block elements and methods.
   *  {Object} Section block elements and methods.
   */
  function toggle(block) {
    block.collapsed ? expand(block) : collapse(block);
    return block;
  }
  
  /**
   * Expand block.
   * @param {Object} block Section block elements and methods.
   *  {Object} Section block elements and methods.
   */
  function expand(block) {
    block.button.setAttribute('aria-expanded', true);
    block.panel.removeAttribute('hidden');
    animate(block.panel, 'normal');
    return block;
  }
  
  /**
   * Collapse block.
   * @param {Object} block Section block elements and methods.
   *  {Object} Section block elements and methods.
   */
  function collapse(block) {
    block.button.setAttribute('aria-expanded', false);
    block.panel.setAttribute('hidden', '');
    animate(block.panel, 'reverse');
    return block;
  }
  
  /**
   * Collapse block.
   * @param {Object} block Section block elements and methods.
   *  {boolean} Collapsed block state.
   */
  function isCollapsed(block) {
    return Boolean(block.button.getAttribute('aria-expanded') === 'false');
  }

  /**
   * Collapse block.
   * @param {HTMLElement} element Block panel element to animate.
   * @param {String} direction Animation direction, normal or reverse.
   *  {undefined} Nothing to return.
   */
  function animate(element, direction) { 
    if (!support.WebAnimations) return;

    element.setAttribute('data-is-animating', true);

    element.animate([
      { height: 0 },
      { height: element.offsetHeight + 'px' }],

      { duration: 240,
        fill: 'both',
        easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)',
        direction: direction
      }

    ).onfinish = function() {
      element.removeAttribute('data-is-animating');
      this.cancel();
    };
  }

  //**************************

  /**
   * Maps all block IDs to exposed block API.
   * @param {Object} config Section and section blocks IDs.
   *  {Object} config Section and section blocks IDs.
   */
  function getBlocks(config) {
    config.blocks = config.blockIds.map(block);
    return config;
  }

  /**
   * Create section block API.
   * @param {String} blockId Section Liquid block ID.
   *  {Object} block elements and methods.
   */
  function block(blockId) {
    return {
      trigger: document.querySelector('[data-faq-trigger="' + blockId + '"]'),
      button: document.querySelector('[data-faq-button="' + blockId + '"]'),
      panel: document.querySelector('[data-faq-panel="' + blockId + '"]'),

      get collapsed() { return isCollapsed(this) },
      select: function select() { return expand(this) },
      deselect: function deselect() { return collapse(this) }
    }
  }

  /**
   * Adds event listeners to block elements.
   * @param {Object} config Section and section blocks IDs.
   *  {Object} config Section and section blocks IDs.
   */
  function setEvents(config) {
    config.blocks.forEach(blockEvents);
    return config;
  }

  /**
   * Pass the Liquid assigned section variabiles.
   * @param {HTMLElement} element Configuration script node.
   *  {Object} Section and section blocks IDs.
   */
  function getConfig(node) {
    return JSON.parse(node.innerHTML);
  }

  /**
   * Feature detection.
   *  {Object} Browser support.
   */
  function getSupport() {
    return {
      WebAnimations: (typeof Element.prototype.animate === 'function')
    }
  }

  //**************************

  /**
   * Creates a new object out of a list of keys and a list of values.
   * Key/value pairing is truncated to the length of the shorter of the two lists.
   * 
   *    zipObj(['a', 'b', 'c'], [1, 2, 3]); //=> {a: 1, b: 2, c: 3}
   * @param {Array} keys The array that will be properties on the output object.
   * @param {Array} values The list of values on the output object.
   *  {Object} The object made by pairing up same-indexed elements of `keys` and `values`.
   */
  function zipObj(keys, values) {
    return keys.reduce(
      function zipObj(acc, key, idx) {
        acc[key] = values[idx];
        return acc;
      }, {}
    )
  }

  /**
   * Performs right-to-left function composition.
   * The rightmost function may have any arity, the remaining functions must be unary.
   * 
   *   function plus1(n) {return n + 1};
   *   function plus2(n) {return n + 2};
   *   compose(plus2,plus1)(1) => 4
   *  {Function} Composed function
   */
  function compose() {
    var funcs = Array.prototype.slice.call(arguments).reverse();
    return function() {
      return funcs.slice(1).reduce(function(res, fn) {
        return fn(res);
      }, funcs[0].apply(undefined, arguments));
    };
  }
  
})(window.SectionsDesign = window.SectionsDesign || {});

How do I get it to display on collection page? I added the line {% include ‘faq’ %} to collection template, but get the error Liquid error (sections/collection-template line 12): Could not find asset snippets/faq.liquid

1 Like

Hey @ChrisW3

The error occurs because you are using the {% include ‘faq’ %} syntax, which is designed to include snippet files. Instead of using {% include ‘faq’ %}, you should use the section inclusion syntax for a file located in the Sections folder.

{% section 'faq' %}

If I managed to help you then, don’t forget to Like it and Mark it as Solution!

Best Regards,
Moeed

{% include ‘faq’ %} will call a code in Snippets, not in Sections, and you cannot call a section into another section. Please try to check if your theme has a collapsible content and add to your Collections from Online Store > Themes > Customize > Collections instead of

Now getting this

Liquid error (sections/collection-template line 131): Cannot render sections inside sections

I see, here’s an alternate solution:

Use a Snippet Instead of a Section
Convert your FAQ section into a snippet. Snippets can be included within sections.

Steps:

  1. Copy the code from Sections/faq.liquid.

  2. Create a new snippet by going to Snippets > Add a new snippet and name it faq.

  3. Paste the copied code into this new snippet file.

Now add this again where you added the {% section ‘faq’ %} code.

{% include 'faq' %}

If I managed to help you then, don’t forget to Like it and Mark it as Solution!

Best Regards,
Moeed

Cant get this to work.

Now getting this:

“Liquid syntax error (line 161): Unknown tag ‘schema’”

I never got an answer to this