---
title: "The For Tag and Liquid Looping"
slug: "liquid-markup-looping"
updated: 2026-04-16T19:43:23Z
published: 2026-04-16T19:43:23Z
---

> ## Documentation Index
> Fetch the complete documentation index at: https://knowledge.technolutions.net/llms.txt
> Use this file to discover all available pages before exploring further.

# The For Tag and Liquid Looping

In [Liquid markup](/v1/docs/getting-started-with-liquid-markup), the `for` tag lets you loop through an array of objects and output information about each object. This is sometimes referred to as **Liquid looping**or **for looping**.

For example, you can take a list of upcoming events and, for each of them, display its title, date, and URL.

Looping through the contents of an array takes two steps:

1. Building the array with a **dictionary subquery export**
2. Using **Liquid markup**to loop through the array

> [!NOTE]
> ✨ Prompting Slate AI
> 
> Ask [Slate AI](/v1/docs/slate-ai) for help writing Liquid markup loops for your specific situation:
> 
> - 💬 *Show me how to use a Liquid loop to list all of a student’s upcoming events, displaying each event’s title and date in a portal message.*
> - 💬 *How do I build a dynamic, data-driven checklist for an applicant dashboard using Liquid tags and loops in a portal widget?*
> - 💬 *Display each of a student's recommenders and their submission status within an interview confirmation email.*

## Step 1: Creating the dictionary subquery export

First, we create a subquery export with a *dictionary*output method. We’ll explore the dictionary method in more detail a little later.

1. [In a query](/v1/docs/queries-overview), create a subquery export.
2. Configure the following settings:
  - **Name:**Enter a name. For example, `received-checklist-items`. The name must be computer friendly (all lowercase and one word, using hyphens `-` or underscores `_` instead of spaces).
  - **Output:**Dictionary
  - **Row Limit:**If you want to return a certain number of objects, enter a number in the row limit setting. Otherwise, leave the row limit setting empty.
3. Create a **join**to the base of the object you want to return. For example, Checklists.
4. Add the **exports**you want returned by your loop. For example, the subject and fulfilled date of a checklist item.
5. Rename the exports so they can be called as Liquid markup tags later on. That is: **all lowercase, separated by hyphens**.

![](https://cdn.us.document360.io/cd8ea7a6-07f3-4846-a554-627ac016d3e3/Images/Documentation/Subquery Exports(1).png)
6. Add any needed filters and sorts.

![](https://cdn.us.document360.io/cd8ea7a6-07f3-4846-a554-627ac016d3e3/Images/Documentation/Filters and Sorts.png)
7. Select **Save.**

![](https://cdn.us.document360.io/cd8ea7a6-07f3-4846-a554-627ac016d3e3/Images/Documentation/Completed Subquery(2).png)

Completed subquery

### How the dictionary output works

The **dictionary**output setting tells Slate to transform a subquery export into an **array**.

An [array](https://en.wikipedia.org/wiki/Array_(data_structure)) is a data structure that stores elements in a list in a specific order.

Slate transforms the subquery export into XML by using the following P-K-V (pair: key, value) data structure:

1. Each **object (here, an application)**is enclosed in a `&lt;row&gt;` tag
2. Each **export**is enclosed in a `&lt;p&gt;` tag.
3. In each `&lt;p&gt;` tag:
  - The export's **name**is enclosed in a `&lt;k&gt;` tag
  - The export's **value** is enclosed in a `&lt;v&gt;` tag

When we run the query containing the subquery export we created, we find a single application is represented like so:

```xml
<row> <!-- object -->
	<p> <!-- export -->
		<k>subject</k> <!-- export name -->
		<v>Official High School Transcript<v> <!-- export value -->
	</p>
	<p> <!-- export -->
		<k>fulfilled-date</k> <!-- export name -->
		<v>01DEC2021<v> <!-- export value -->
	</p>
</row>

<row>
	<p>
		<k>subject</k>
		<v>Letter of Recommendation<v>
	</p>
	<p>
		<k>fulfilled-date</k>
		<v>11NOV2021<v>
	</p>
</row>
```

Based on this output, we see that the application has:

- **two**fulfilled checklist items (the `&lt;row&gt;` tags)
- the attributes described by their respective `&lt;k&gt;` and `&lt;v&gt;` tags

## Step 2: Looping through the array using Liquid markup

Now that you have a dictionary subquery export returning the data you want to use, Liquid markup can **loop**through the data and output this information.

The basic form this loop takes is: *For each object in this array of objects, do something.*

Continuing our example above, we’ll call each object `checklist` and use the `received-checklist-items` export as our array.

#### Initiate the loop

This Liquid markup tag tells Slate which object to loop over.

In the source editor of whatever you’re editing:

1. Enter the opening bracket and percent sign to create a Liquid markup tag: `{%`
2. Enter “for” to begin the loop: `{% for`
3. In the for loop, define what you want each object to be called (we will call them checklists): `{% for checklist`
4. Identify the array by entering “in” and the name of the array (the subquery export “received-checklist-items”): `{% for checklist in received-checklist-items`
5. Close the Liquid markup tag: `{% for checklist in received-checklist-items %}`

**Result:**

```plaintext
{% for checklist in received-checklist-items %}
```

#### Define the loop action

With the loop initiated, we now tell Slate what should be done with the objects it retrieves.

Here, we’re going to tell Slate to present these objects in a line of text: `&lt;SUBJECT&gt;: Received on &lt;DATE&gt;`, where `&lt;SUBJECT&gt;` and `&lt;DATE&gt;` are the checklist item’s subject and fulfilled date.

To call the checklist’s subject, we use the format `{{object.export}}`, where:

- `object` is the name we established in the for loop initiation (“checklist”)
- `export` is the name of the subquery export (“subject”)

We’ll follow the same format for the fulfilled date.

In the source editor:

1. Hit return to start a new line.
2. Enter `{{checklist.subject}}: Received on {{checklist.fulfilled-date}}`.

**Result:**

```plaintext
{% for checklist in received-checklist-items %} 
   {{checklist.subject}}: Received on {{checklist.fulfilled-date}}
```

#### Terminate the loop

On a new line, end the loop by using the `endfor` tag.

**Result:**

```plaintext
{% for checklist in received-checklist-items %} 
   {{checklist.subject}}: Received on {{checklist.fulfilled-date}} 
{% endfor %}
```

#### Verify the output

Based on our example data, we would receive the following output:

```plaintext
Official High School Transcript: Received on 01DEC2021 Letter of Recommendation: Received on 11NOV2021
```

We’ve got everything we wanted, but the result is a little hard to read; we’ll learn how we can **format our output**in the next section.

## Helper variables

Use **forlooper helpers**to grab additional attributes about your loop, such as the current index number.

Helper variables are useful for assessing properties of a for loop:

| **Helper Variable** | **Function** |
| --- | --- |
| `forloop.length` | Length of the loop |
| `forloop.index` | Number of current loop iteration |
| `forloop.rindex` | Number of remaining loop iteration(s) |
| `forloop.first` | Determines if the current iteration is the first iteration |
| `forloop.last` | Determines if the current iteration is the last iteration |

## Formatting your output

You have many options on how you want to show each object in the array.

Here are some different examples using our example above:

#### Each object on a new line

```xml
{% for checklist in received-checklist-items %}
  <p>{{checklist.subject}}: Received on {{checklist.fulfilled-date}}</p>
{% endfor %}
```

#### Each object as an item in an ordered list

```xml
<ol>
  {% for checklist in received-checklist-items %}     
        <li>{{checklist.subject}}: Received on {{checklist.fulfilled-date}}</li>
  {% endfor %}
</ol>
  
```

#### Each object as an item in an unordered list

```xml
<ul>
  {% for checklist in received-checklist-items %}
    <li>{{checklist.subject}}: Received on {{checklist.fulfilled-date}}</li>
  {% endfor %}
</ul>
```

#### Each object as a row in a table

```xml
<table>
<thead>
  <tr>
    <th>Checklist Item</th>
    <th>Received Date</th>
    </tr>
</thead>
<tbody>
{% for checklist in received-checklist-items %}
  <tr>
    <td>{{checklist.subject}}</td>
    <td>{{checklist.fulfilled-date}}</td>
  </tr>
{% endfor %}
</tbody>
</table>
```

**📖**See the [Shopify documentation on Liquid iteration](https://shopify.dev/docs/api/liquid/tags/iteration-tags).

## Related

- [Getting Started with Liquid Markup](/getting-started-with-liquid-markup.md)
