Homepage

Liquid - Tags: Loops

Last edit: Jul 14, 2023

for

Liquid allows for loops over collections to iterate over arrays, hashes, and ranges of integers.

Iterating over an array


{% for item in array %}
  {{ item }}
{% endfor %}

Iterating over a hash

When iterating a hash, item[0] contains the key, and item[1] contains the value:


{% for item in hash %}
  {{ item[0] }}: {{ item[1] }}
{% endfor %}

Instead of looping over an existing collection, you can also loop through a range of numbers.
Ranges look like (1..10) — parentheses containing a start value, two periods, and an end value.
The start and end values must be integers or expressions that resolve to integers.

Input if item.quantity is 4


{% for i in (1..item.quantity) %}
  {{ i }}
{% endfor %}

Output

1,2,3,4

Breaking and continuing

You can exit a loop early with the following tags:

  • {% continue %}: immediately end the current iteration, and continue the for loop with the next value.
  • {% break %}: immediately end the current iteration, then completely end the for loop.
    Both of these are only useful when combined with something like an if statement.

{% for page in pages %}

{% comment %}
  Skip anything in the hidden_pages array,
  but keep looping over the rest of the values
{% endcomment %}

  {% if hidden_pages contains page.url %}
    {% continue %}
  {% endif %}

{% comment %} If it's not hidden, print it. {% endcomment %}

  * [page.title](page.url)
{% endfor %}



{% for page in pages %}
  * [page.title](page.url)

{% comment %}
  After we reach the "cutoff" page,
  stop the list and get on with whatever's after the "for" loop:
{% endcomment %}

  {% if cutoff_page == page.url %}
    {% break %}
  {% endif %}

{% endfor %}

Helper variables

During every for loop, the following helper variables are available for extra styling needs:

Variable Description
forloop.length length of the entire for loop
forloop.index index of the current iteration
forloop.index0 index of the current iteration (zero-based)
forloop.rindex how many items are still left?
forloop.rindex0 how many items are still left? (zero-based)
forloop.first is this the first iteration?
forloop.last is this the last iteration?
forloop.parentloop Provides access to the parent loop, if present.

Find examples at the Liquid Objects page.

Optional arguments

There are several optional arguments to the for tag that can influence which items you receive in your loop and what order they appear in:

  • limit:<INTEGER> lets you restrict how many items you get.
  • offset:<INTEGER> lets you start the collection with the nth item.
  • reversed iterates over the collection from last to first.

Restricting elements

array = [1,2,3,4,5,6]


{% for item in array limit:2 offset:2 %}
  {{ item }}
{% endfor %}

Output

3,4

Reversing the loop:


{% for item in collection reversed %}
  {{ item }}
{% endfor %}

Handling an empty collection

A for loop can take an optional else clause to display a block of text when there are no items in the collection:

items => []


{% for item in items %}
  {{ item.title }}
{% else %}
  There are no items!
{% endfor %}

cycle

Loops through a group of strings and outputs them in the order that they were passed as parameters. Each time cycle is called, the next string that was passed as a parameter is output.


{% for i in (1..4) -%}
  {% cycle 'one', 'two', 'three' %}
{% endfor -%}

will result in

one
two
three
one

Though cycle is often used within a for loop block, it also works on its own by placing multiple copies of the tag on the page. Liquid treats each tag as part of the same group, even if their contents are different.


{% cycle 'one', 'two', 'three' %}
{% cycle 'banana', 'apple', 'orange' %}
{% cycle 'one', 'two', 'three' %}
{% cycle 'one', 'two', 'three' %}

will result in

one
apple
three
one

If you want to have total control over cycle groups, you can optionally specify the name of the group. This can even be a variable.


{% cycle 'group 1': 'one', 'two', 'three', 'four' %}
{% cycle 'group 1': 'one', 'two', 'three', 'four' %}
{% cycle 'group 2': 'one', 'two', 'three', 'four' %}
{% cycle 'group 2': 'one', 'two', 'three', 'four' %}
{% cycle 'group 1': 'one', 'two', 'three', 'four' %}
{% cycle 'group 1': 'one', 'two', 'three', 'four' %}

will result in

one
two
one
two
three
four

Liquid assumes that each cycle tag without a name is part of the same nameless group. For example:


{% cycle 'A', 'B', 'C', 'D' %}
{% cycle 'group 3': 'one', 'two', 'three', 'four' %}
{% cycle 'group 4': 'one', 'two', 'three', 'four' %}
{% cycle 'group 4': 'one', 'two', 'three', 'four' %}
{% cycle 'group 3': 'one', 'two', 'three', 'four' %}
{% cycle 'group 3': 'one', 'two', 'three', 'four' %}
{% cycle 'A', 'B', 'C', 'D' %}

will result in

A
one
one
two
two
three
B

ifchanged

The ifchanged tag is typically called inside a {% for %} loop because it executes a block of code but only outputs the result if this is the first time it was called or if the previous call had a different result.

Input


{% assign list = "1,1,1,1,3,3,3,2,1,3,1,2" | split: "," %}
{% for item in list -%}
    {%- ifchanged %} {{ item }} {% endifchanged -%}
{%- endfor %}

Output


1 3 2 1 3 1 2

tablerow

Generates rows for an HTML table. Must be wrapped in opening <table> and closing </table> HTML tags. The tablerowloop object describes the full list of attributes available within a tablerow.

Input


<table>
  {% tablerow product in collection.products %}
    {{ product.title }}
  {% endtablerow %}
</table>

Output

<table>
  <tr class="row1">
    <td class="col1">Cool Shirt</td>
    <td class="col2">Alien Poster</td>
    <td class="col3">Batman Poster</td>
    <td class="col4">Bullseye Shirt</td>
    <td class="col5">Another Classic Vinyl</td>
    <td class="col6">Awesome Jeans</td>
  </tr>
</table>

tablerow tag parameters

cols

Defines how many columns the tables should have.

Input

<table>
  {% tablerow product in collection.products cols:2 %}
    {{ product.title }}
  {% endtablerow %}
</table>

Output
<table>
  <tr class="row1">
    <td class="col1">Cool Shirt</td>
    <td class="col2">Alien Poster</td>
  </tr>
  <tr class="row2">
    <td class="col1">Batman Poster</td>
    <td class="col2">Bullseye Shirt</td>
  </tr>
  <tr class="row3">
    <td class="col1">Another Classic Vinyl</td>
    <td class="col2">Awesome Jeans</td>
  </tr>
</table>

limit

Exits the tablerow loop after a specific index.


{% tablerow product in collection.products cols:2 limit:3 %}
  {{ product.title }}
{% endtablerow %}

offset

Starts the tablerow loop at a specific index.


{% tablerow product in collection.products cols:2 offset:3 %}
  {{ product.title }}
{% endtablerow %}

range

Defines a range of numbers to loop through. The range can be defined by both literal and variable numbers.


<table>
  {% tablerow i in (3..5) %}
    {{ i }}
  {% endtablerow %}
</table>

{% assign num = 4 %}
<table>
  {% tablerow i in (1..num) %}
    {{ i }}
  {% endtablerow %}
</table>

Note

This topic is a compilation of knowledge found at: Shopify Themes, Liquid Documentation, Liquid Gem Documentation, and Liquid for Designers.

Questions?

We are always happy to help with any questions you may have.

contact us