Symfony News

Better White Space Control in Twig Templates

Whitespace control in Twig templates allows you to control the indentation and spacing of the generated contents (usually HTML code). Most of the times you should ignore this feature, because the HTML contents are minified and compressed before sending them to the users, so trying to generate perfectly aligned HTML code is just a waste of time.

However, there are some specific cases where whitespace can change how things are displayed. For example, when an <a> element contains white spaces after the link text and the link displays an underline, the whitespace is visible. That's why Twig provides multiple ways of controlling white spaces. In recent Twig versions, we've improved those features.

New whitespace trimming options

Contributed by
Fabien Potencier
in #2925.

Consider the following Twig snippet:

1
2
3
4
5
6
7
<ul>
    <li>
        {% if some_expression %}
            {{ some_variable }}
        {% endif %}
    </li>
</ul>

If the value of some_variable is 'Lorem Ipsum', the HTML generated when the if expression matches, would be the following:

1
2
3
4
5
<ul>
    <li>
            Lorem Ipsum
        </li>
</ul>

Twig only removes by default the first \n character after each Twig tag (the \n after the if and endif tags in the previous example). If you want to generate HTML code with better indention, you can use the - character, which removes all white spaces (including newlines) from the left or right of the tag:

1
2
3
4
5
6
7
<ul>
    <li>
        {%- if some_expression %}
            {{- some_variable -}}
        {% endif -%}
    </li>
</ul>

The output is now:

1
2
3
<ul>
    <li>Lorem Ipsum</li>
</ul>

Starting from Twig 1.39 and 2.8.0, you have another option to control whitespace: the ~ character (which can be applied to {{, {% and {#). It's similar to -, with the only difference that ~ doesn't remove newlines:

1
2
3
4
5
6
7
<ul>
    <li>
        {%~ if some_expression %}
            {{ some_variable -}}
        {% endif ~%}
    </li>
</ul>

The output now contains the newlines after/before the <li> tags, so the generated HTML is more similar to the original Twig code you wrote:

1
2
3
4
5
<ul>
    <li>
        Lorem Ipsum
    </li>
</ul>

Added a spaceless filter

Contributed by
Fabien Potencier
in #2872.

In previous Twig versions, there was a tag called {% spaceless %} which transformed the given string content to remove the white spaces between HTML tags. However, in Twig, transforming some contents before displaying them is something done by filters.

That's why, starting from Twig 1.38 and 2.7.3, the spaceless tag has been removed in favor of the spaceless filter, which works exactly the same:

1
{{ some_variable_with_HTML_content|spaceless }}

However, this is commonly used with the alternative way of applying some filter to some HTML contents:

1
2
3
4
5
-{% spaceless %}
+{% apply spaceless %}
    {# some HTML content here #}
-{% endspaceless %}
+{% endapply %}

In case you missed it, the apply tag was recently added to replace the previous filter tag.

In any case, even after these changes, it's still recommend to not use the spaceless filter too much. The removal of white spaces with this filter happens at runtime, so calling it repeatedly can hurt performance.

Fine-grained escaping on ternary expressions

Contributed by
Fabien Potencier
in #2934.

This new feature introduced in Twig 1.39 and 2.8 is not related to whitespace control, but it's an important new feature to consider in your templates. Consider the following example and the results rendered in Twig versions before 1.39 and 2.8:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{% set foo = '<strong>foo</strong>' %}
{% set bar = '<strong>bar</strong>' %}

{{ false ? '<strong>bar</strong>' : foo|raw }}
{# renders as '<strong>foo</strong>' #}

{{ false ? bar : foo|raw }}
{# renders as '&lt;strong&gt;foo&lt;/strong&gt;' #}

{{ (false ? bar : foo)|raw }}
{# renders as '<strong>foo</strong>' #}

The reason why this example worked in that way in previous Twig versions is that in the first ternary statement, foo is marked as being safe and Twig does not escape static values. In the second ternary statement, even if foo is marked as safe, bar remains unsafe and so is the whole expression. The third ternary statement is marked as safe and the result is not escaped.

This behavior was confusing to lots of designers and developers. That's why, starting from Twig 1.39 and 2.8, the result of this example has changed as follows:

1
2
3
4
5
6
7
{% set foo = '<strong>foo</strong>' %}
{% set bar = '<strong>bar</strong>' %}

{{ false ? '<strong>bar</strong>' : foo|raw }}
{{ false ? bar : foo|raw }}
{{ (false ? bar : foo)|raw }}
{# renders as '<strong>foo</strong>' in all cases #}

Be trained by Symfony experts - 2019-06-24 Berlin - 2019-06-24 Berlin - 2019-06-24 Clichy


About us

What a Symfony developer should know about the framework: News, Jobs, Tweets, Events, Videos,...

Resources

Find us on Twitter

Find us on Facebook