Skip to content

Whitespace control

By default, all whitespace immediately before and after a tag is preserved. This can result in a lot of unwanted whitespace.

<ul>
{% for x in (1..4) %}
  <li>{{ x }}</li>
{% endfor %}
</ul>
output
<ul>

  <li>1</li>

  <li>2</li>

  <li>3</li>

  <li>4</li>

</ul>

By inserting special characters inside tags and output statements, template authors can choose what whitespace trimming rules to apply. - is used to remove all whitespace until the next printing character, and ~ will trim immediate carriage returns and newlines, leaving spaces and tabs.

There's also +, which has no effect with the default trim mode.

<ul>
{% for x in (1..4) ~%}
  <li>{{ x }}</li>
{% endfor -%}
</ul>
output
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
</ul>

Default trim

You can change the default whitespace trimming mode using the default_trim argument when constructing an Environment.

Setting default_trim to WhitespaceControl.MINUS will automatically remove all whitespace unless it is explicitly overridden by the template author using + or ~.

Setting default_trim to WhitespaceControl.TILDE will automatically remove immediate carriage returns an newlines unless it is explicitly overridden by the template author using + or -.

Customizing whitespace control

Environment.trim() is called when stripping whitespace from template content. You can override trim() in an Environment subclass to define your own whitespace control behavior, interpreting -, + and ~ however you see fit.

from liquid2 import Environment
from liquid2 import WhitespaceControl

class MyLiquidEnvironment(Environment):

    def trim(
        self,
        text: str,
        left_trim: WhitespaceControl,
        right_trim: WhitespaceControl,
    ) -> str:
        """Return _text_ after applying whitespace control."""
        if left_trim == WhitespaceControl.DEFAULT:
            left_trim = self.default_trim

        if right_trim == WhitespaceControl.DEFAULT:
            right_trim = self.default_trim

        if left_trim == right_trim:
            if left_trim == WhitespaceControl.MINUS:
                return text.strip()
            if left_trim == WhitespaceControl.TILDE:
                return text.strip("\r\n")
            return text

        if left_trim == WhitespaceControl.MINUS:
            text = text.lstrip()
        elif left_trim == WhitespaceControl.TILDE:
            text = text.lstrip("\r\n")

        if right_trim == WhitespaceControl.MINUS:
            text = text.rstrip()
        elif right_trim == WhitespaceControl.TILDE:
            text = text.rstrip("\r\n")

        return text

Suppressing blank control flow blocks

It is assumed that a conditional block containing no template content or output statements should not render its whitespace. For example, the newlines between the tags and spaces before assign here are automatically suppressed, regardless of the default trim mode.

{% if true %}
    {% assign x = y %}
{% endif %}

You can disable this feature by subclassing Environment and setting the suppress_blank_control_flow_blocks class attribute to False.

from liquid2 import Environment

class MyEnvironment(Environment):
    suppress_blank_control_flow_blocks = False