Skip to main content
Liquid 101

Start building custom TRMNL plugins with no coding experience.

TRMNL Team avatar
Written by TRMNL Team
Updated today

When building Private Plugins in TRMNL, we need a way to display the data gathered by the plugin in our TRMNL screen.

This is where "Liquid" comes in -- it's a templating language that bridges the gap between raw data and the visual layout of your plugin.

Quickstart

Let's say we have a plugin that receives data about a task to be done, and this is represented by the following JSON data structure:

{
"name": "Walk the dog",
"date": "2025-02-24",
"late": true,
"location": {
"city": "New York"
}
}

To display this data in our TRMNL's screen, we can write a simple HTML snippet like below and the {{ name }} and {{ date }} would automatically be replaced by the corresponding values on the JSON.

<p>Task "{{ name }}" is due on {{ date }}</p>

Result:

Task "Walk the dog" is due on 2025-02-24

With this small example, we have just learned the most basic concept of Liquid. Enclosing any property of our JSON document between {{ and }} is how we output the value of a property or a variable.

We can also do what's called "dot notation" to navigate on the JSON structure and display deeply nested properties like this location.city example:

<p>Task "{{ name }}" is due on {{ date }} in {{ location.city }}</p>

Result:

Task "Walk the dog" is due on 2025-02-24 in New York

Variables

You can also create variables in Liquid and assign values to them for later display. Usually we employ variables when we need to modify the JSON data of the plugin, for example by doing some math with one the properties.

To create a variable we use the special keyword assign like below:

{% assign my_variable = "my value" %}

We can now display this value by doing {{ my_variable }} like we did before with the JSON properties.

Also notice how Liquid code is written between the delimiters {% and %}.

Conditionals

We can create conditional expressions in Liquid that are evaluated against our data and decide if a block of code is executed or not.

Let's say we want to show a warning emoji (⚠️) next to the task's date if it's running late. For this we can create an if expression that evaluates if the value of the late property equals true.

{% if late == true %}
<p>Task "{{ name }}" is due on ⚠️ {{ date }} ⚠️</p>
{% else %}
<p>Task "{{ name }}" is due on {{ date }}</p>
{% endif %}

Result:

Task "Walk the dog" is due on ⚠️ 2025-02-24 ⚠️

Conditionals do not need to check for equality only. Liquid supports all the standard logical operators to check for difference, greater than, less than or equal, and so on.

Handling Lists

There are many cases where the data we want to display is actually a list of things.

Let's reimagine our task example as a list of tasks represented by the following JSON structure:

{
"tasks": [
{
"name": "Walk the dog",
"date": "2025-02-24",
"late": true,
},
{
"name": "Half-Life 3 Release",
"date": "2033-10-08",
"late": false,
}
]
}

We now have a property called tasks that holds a list with two tasks inside. To display all the tasks on our TRMNL we need to loop through the list and display the properties of each task individually. This can be achieved with iteration, or a for loop as we usually call it.

Rewriting our code to handle the list and print each item looks like this:

{% for task in tasks %}
<p>Task "{{ task.name }}" is due on {{ task.date }}</p>
{% endfor %}

Result:

Task "Walk the dog" is due on 2025-02-24
Task "Half-Life 3 Release" is due on 2033-10-08

As you can see, the code for task in tasks actually creates a temporary variable called task that holds all the properties of the current task being iterated. That's why we are able to display the property values using {{ task.name }} instead of just {{ name }} as we did before.

Putting it all together

Now that we already know how to apply conditionals and handle lists, mixing both of these concepts is where all the fun begins!

Let's say we only want to display the tasks that are currently late, we can combine for and if to loop through the list and filter only the tasks we're interested in:

{% for task in tasks %}
{% if task.late == true %}
<p>Task "{{ task.name }}" is due on {{ task.date }}</p>
{% endif %}
{% endfor %}

Another way of accomplishing this would be using a "filter", as we'll see on the next section.

Filters

Filters are a very powerful construct in Liquid as they allow us to manipulate and transform our data in many different ways.

Let's start with a very simple example, where we would like to display our task name with uppercase letters. We can employ the upcase filter for this:

<p>Task "{{ task.name | upcase }}" is due on {{ task.date }}</p>

Result:

Task "WALK THE DOG" is due on 2025-02-24

Now let's rewrite the example above that showed only the late tasks to use the where filter instead. This filter acts upon a list of objects, and returns a new list with only the objects that pass a certain criteria:

{% assign late_tasks = tasks | where: "late", true %}
{% for task in late_tasks %}
<p>Task "{{ task.name }}" is due on {{ task.date }}</p>
{% endfor %}

Using filters is just a matter of "piping" variables into them. This means you can chain filters together to achieve the desired result in just one line of code. Check out this example that calculates a percentage:

{% assign value = 20.0 %}
{% assign total = 50.0 %}
{% assign percentage = value | divided_by: total | times: 100 | round %}
<p>{{ value }} is {{ percentage }}% of {{ total }}</p>

Result:

20 is 40% of 50

Liquid has more than 50 filters available to help us with all kinds of data manipulation, doing math, handling dates, filtering lists and a lot more.

Be sure to check the resources below for the full documentation of Liquid and some of TRMNL's own custom filters.

More Resources

Did this answer your question?