Your comprehensive guide for ERB front-end view templates.
Read more
This post is an iteration on ERB and Twig Cross-Reference for Front-End Development. That post is geared towards developers who want to translate their Twig knowledge to ERB, or vice versa. You may also be interested in Fundamental ERB for Front-End Development.
Contents
Twig is SensioLabs’ Django- / Jinja-like templating language for PHP. The recommended extension for Twig files is .twig, .<compiled_extension>.twig is useful, and .html —though inaccurate— is common in front-end templating. It’s used by SensioLabs’ Symfony; by Drupal 8, which is built on Symfony; and by Craft CMS.
Twig is a great language for building web front ends: it is full-featured without having more than one person could hope to learn, it reads fairly closely to English, and it has great official documentation. Twig is especially notable for its powerful support for complex inheritance across templates. Check out the use tag, the embed tag, and the block() function.
Twig even has Javascript implementations, making it easy to fit into projects built on the JS ecosystem. A quick overview to help you pick the one that best suits yours needs:
embed tag) but it currently comes closer than Nunjucks does and, since its goal is to duplicate Twig, it likely always will. The Twig.js Gulp plugin is gulp-twig.To learn Twig, read through the official documentation, and try things out in twigfiddle.
{# … #}
twig{# comment #}
twig{# comment #}
{# … #}
twig{#block comment#}
twig{#block comment#}
or
twignot a comment {# blockcomment #} not a comment
twignot a comment {# blockcomment #} not a comment
{{ }}
twig{{ "print this" }} {# output: `print this` #}{{ 1 + 2 }} {# output: `3` #}
twig{{ "print this" }} {# output: `print this` #}{{ 1 + 2 }} {# output: `3` #}
{% … %}
twig{% if … %} … {% endif %}
twig{% if … %} … {% endif %}
if…elseif…endif
twig{% if x %}y{% elseif z == n %}{# note the spelling of elseif #}0{% else %}1{% endif %}
twig{% if x %}y{% elseif z == n %}{# note the spelling of elseif #}0{% else %}1{% endif %}
Twig supports “condition ? iftrue : iffalse”, and “ifselftrue ?: otherwise”.
twig{# assuming x, y, z, and n are defined and/or Twig's strict variables option is turned off #}{# if x then y #}{{ x ? y }}{# if x is true, y. otherwise, if z equals n then 0. otherwise 1 #}{{ x ? y : z == n ? 0 : 1 }}{# ternary operator: x if x is true, otherwise y #}{{ x ?: y }}
twig{# assuming x, y, z, and n are defined and/or Twig's strict variables option is turned off #}{# if x then y #}{{ x ? y }}{# if x is true, y. otherwise, if z equals n then 0. otherwise 1 #}{{ x ? y : z == n ? 0 : 1 }}{# ternary operator: x if x is true, otherwise y #}{{ x ?: y }}
As in PHP, 0 is False in Boolean contexts
twig{{ false ? 'truthy' : 'falsy' }} {# output: `falsy` #}{{ 0 ? 'truthy' : 'falsy' }} {# output: `falsy` #}
twig{{ false ? 'truthy' : 'falsy' }} {# output: `falsy` #}{{ 0 ? 'truthy' : 'falsy' }} {# output: `falsy` #}
set
twig{% set var = 1 %}{% set anotherVar = 0 %}{% set falseVar = false %}{{ var ? 2 }} {# output: `2` #}{{ anotherVar ? 2 }} {# output: null - Twig, unlike PHP, equates 0 with falsehood #}{{ falseVar ? '' : 2 }} {# output `2` #}
twig{% set var = 1 %}{% set anotherVar = 0 %}{% set falseVar = false %}{{ var ? 2 }} {# output: `2` #}{{ anotherVar ? 2 }} {# output: null - Twig, unlike PHP, equates 0 with falsehood #}{{ falseVar ? '' : 2 }} {# output `2` #}
Twig can define multiple variables in a single call — just keep in mind that developers not used to this might overlook the multiple declarations!
twig{% set x, y, z = 1, 2, 3 %}
twig{% set x, y, z = 1, 2, 3 %}
(A value must be explicitly provided for each variable: {% set x, y = 1 %} will error.)
Use the set tag’s form set x…endset to capture chunks of text
twig{% set longVar %}<div>…</div>{% endset %}{{ longVar }}
twig{% set longVar %}<div>…</div>{% endset %}{{ longVar }}
is defined
Especially useful when Twig’s strict variables option is turned on, in which case referring to an undefined variable will throw an error.
twig{# output: Twig_Error_Runtime: Variable "x" does not exist. #}{{ x }}{# output: the content if var is defined #}{% if var is defined %}…{% endif %}{# output: `advance` if var is defined, otherwise `fallback` #}{{ var is defined ? advance : fallback }}
twig{# output: Twig_Error_Runtime: Variable "x" does not exist. #}{{ x }}{# output: the content if var is defined #}{% if var is defined %}…{% endif %}{# output: `advance` if var is defined, otherwise `fallback` #}{{ var is defined ? advance : fallback }}
??, the null coalescing operator
twig{# output: `var` if it is defined and not null, otherwise `fallback` #}{{ var ?? fallback }}{# common use cases:1. output a variable only if it is defined #}{{ var ?? null }}{# set a variable with a fallback #}{% set x = y ?? null %}
twig{# output: `var` if it is defined and not null, otherwise `fallback` #}{{ var ?? fallback }}{# common use cases:1. output a variable only if it is defined #}{{ var ?? null }}{# set a variable with a fallback #}{% set x = y ?? null %}
#{var}
twig{% set x = 1 %}{{ "this is interpolated #{x}" }}{# output: `this is interpolated: 1` #}
twig{% set x = 1 %}{{ "this is interpolated #{x}" }}{# output: `this is interpolated: 1` #}
~ (tilde). Note that strings and numbers can be freely concatenated.
twig{% set string_variable = 'world' %}{% set number_variable = 2 %}{{ 'hello ' ~ string_variable }} {# output: `hello world` #}{{ "example #{number_variable}" }} {# output: `example 2` #}{{ 'example ' ~ 3 }} {# output: `example 3` #}
twig{% set string_variable = 'world' %}{% set number_variable = 2 %}{{ 'hello ' ~ string_variable }} {# output: `hello world` #}{{ "example #{number_variable}" }} {# output: `example 2` #}{{ 'example ' ~ 3 }} {# output: `example 3` #}
for i in n…endfor
twig{% set items = ['a','b','c'] %}{# output: `...` #}{% for i in 0..items.length %}.{% endfor %}{# output: `a b c ` #}{% for item in items %}{{item}}{% endfor %}
twig{% set items = ['a','b','c'] %}{# output: `...` #}{% for i in 0..items.length %}.{% endfor %}{# output: `a b c ` #}{% for item in items %}{{item}}{% endfor %}
loop.index0
twig{% for item in items %}{{loop.index0}}. {{item}}{% endfor %}
twig{% for item in items %}{{loop.index0}}. {{item}}{% endfor %}
loop.index
twig{% for item in items %}{{loop.index}}. {{item}}{% endfor %}
twig{% for item in items %}{{loop.index}}. {{item}}{% endfor %}
for i in n…endfor
twig{% set items = ['a','b','c'] %}{# output: `...` #}{% for i in 0..items.length %}.{% endfor %}{# output: `a b c ` #}{% for item in items %}{{item}}{% endfor %}
twig{% set items = ['a','b','c'] %}{# output: `...` #}{% for i in 0..items.length %}.{% endfor %}{# output: `a b c ` #}{% for item in items %}{{item}}{% endfor %}
The |json_encode() filter formats an object’s data.
twig{# for some object `posts` #}{{ posts|json_encode }}
twig{# for some object `posts` #}{{ posts|json_encode }}
The dump() function outputs information about a variable.
twig{# for some object `posts` #}{{ dump(posts) }}
twig{# for some object `posts` #}{{ dump(posts) }}
Note: dump must be enabled. Some implementations make it available out of the box (for example, Craft CMS in dev mode).
|slice(start,count) or [start:count]
twig{{ [1,2,3,4]|slice(1) }} {# output: `Array` #}{{ [1,2,3,4]|slice(1,2) }} {# output: `Array` #}
twig{{ [1,2,3,4]|slice(1) }} {# output: `Array` #}{{ [1,2,3,4]|slice(1,2) }} {# output: `Array` #}
Note: The output of the above Twig examples is Array, because in Twig the output of {{ [anArray] }} is Array. If you need to print an array, use |json_encode:
twig{{ [1,2,3,4]|slice(1)|json_encode() }} {# output: `[2,3,4]` #}{{ [1,2,3,4]|slice(1,2)|json_encode() }} {# output: `[2,3]` #}
twig{{ [1,2,3,4]|slice(1)|json_encode() }} {# output: `[2,3,4]` #}{{ [1,2,3,4]|slice(1,2)|json_encode() }} {# output: `[2,3]` #}
In execution, no special steps are necessary:
twig{% set myArray = [1,2,3,4] %}…
twig{% set myArray = [1,2,3,4] %}…
count items[:count]
twig{{ [1,2,3,4][:2]|json_encode() }} {# output: `[1,2]` #}
twig{{ [1,2,3,4][:2]|json_encode() }} {# output: `[1,2]` #}
start item[start:]
twig{{ [1,2,3,4][2:]|json_encode() }} {# output: `[3,4]` #}
twig{{ [1,2,3,4][2:]|json_encode() }} {# output: `[3,4]` #}
Trim leading or trailing whitespace by adding a - inside in an opening or close delimiter, respectively:
twig{% something -%}1{%- something_else -%}2{%- last_thing %}
twig{% something -%}1{%- something_else -%}2{%- last_thing %}
is equivalent to
twig{% something %}1{% something_else %}2{% last_thing %}
twig{% something %}1{% something_else %}2{% last_thing %}
Twig doesn’t care what language you are compiling to, but it does provide a special spaceless tag for use with HTML.
twig{% spaceless %}<div>…</div><span>…</span>{% endspaceless %}
twig{% spaceless %}<div>…</div><span>…</span>{% endspaceless %}
is equivalent to
twig<div>…</div><span>…</span>
twig<div>…</div><span>…</span>
Note that this spaceless has limited powers:
it isn’t recursive
twig{% spaceless %}<div><div>…</div><div><span>…</span>{% endspaceless %}
twig{% spaceless %}<div><div>…</div><div><span>…</span>{% endspaceless %}
is equivalent to
twig<div><div>…</div><div><span>…</span>
twig<div><div>…</div><div><span>…</span>
and content between HTML tags will disrupt it
twig{% spaceless %}<div>…</div>sorry, spaceless<span>…</span>{% endspaceless %}
twig{% spaceless %}<div>…</div>sorry, spaceless<span>…</span>{% endspaceless %}
is equivalent to
twig<div>…</div>sorry, spaceless<span>…</span>
twig<div>…</div>sorry, spaceless<span>…</span>
Use dot notation or subscript syntax to access attributes of a variable:
twig{% set myVar = {hello: 'world'} %}{{ myVar.hello }} {# output: world #}{{ myVar['hello'] }} {# output: world #}
twig{% set myVar = {hello: 'world'} %}{{ myVar.hello }} {# output: world #}{{ myVar['hello'] }} {# output: world #}
For a layout file that pulls in page:
block + extends in child, block in parent.
layout.html.twig
twig{% block myBlock '' %}{# or #}{% block myBlock %}{% endblock %}{# or #}{% block myBlock %}{% endblock myBlock %}
twig{% block myBlock '' %}{# or #}{% block myBlock %}{% endblock %}{# or #}{% block myBlock %}{% endblock myBlock %}
page.html.twig
twig{% extends 'layout.html.twig' %}{% block myBlock %}the content{% endblock %}
twig{% extends 'layout.html.twig' %}{% block myBlock %}the content{% endblock %}
or if all the content is a variable x, page.html.twig
twig{% extends 'layout.html.twig' %}{% block myBlock x %}
twig{% extends 'layout.html.twig' %}{% block myBlock x %}
or if all the content is a single string, page.html.twig
twig{% extends 'layout.html.twig' %}{% block myBlock "#{x} content" %}{# or #}{% extends 'layout.html.twig' %}{% block myBlock x ~ "content" %}
twig{% extends 'layout.html.twig' %}{% block myBlock "#{x} content" %}{# or #}{% extends 'layout.html.twig' %}{% block myBlock x ~ "content" %}
or if all the content is a single literal string, page.html.twig
twig{% extends 'layout.html.twig' %}{% block myBlock 'the content' %}{# or #}{% block myBlock "the content" %}
twig{% extends 'layout.html.twig' %}{% block myBlock 'the content' %}{# or #}{% block myBlock "the content" %}
main.html.twig
twig{% block content %}default content{% block sub_content '' %}{% endblock %}
twig{% block content %}default content{% block sub_content '' %}{% endblock %}
override-content.html.twig
twig{% extends 'main.html.twig' %}{% block content %}the content{% endblock %}
twig{% extends 'main.html.twig' %}{% block content %}the content{% endblock %}
Result of override-content.html.twig:
default content
default content
override-subcontent.html.twig
twig{% extends 'main.html.twig' %}{% block subcontent %}the sub-content{% endblock %}
twig{% extends 'main.html.twig' %}{% block subcontent %}the sub-content{% endblock %}
Result of override-subcontent.html.twig:
default contentthe sub-content
default contentthe sub-content
include tag
twig{% include 'path/to/x' %}
twig{% include 'path/to/x' %}
include function
twig{{ include('path/to/x') }}
twig{{ include('path/to/x') }}
The include tag passes the entire parent context to the included file by default:
twig{% set a = 1 %}{% set b = 2 %}{% include 'path/to/x' %} {# in path/to/x a=1 and b=2 #}
twig{% set a = 1 %}{% set b = 2 %}{% include 'path/to/x' %} {# in path/to/x a=1 and b=2 #}
To pass only certain data, use include with only:
twig{% set a = 1 %}{% set b = 2 %}{% include 'path/to/x' with {a:a} only %}{# in path/to/x a=1 and b does not exist #}
twig{% set a = 1 %}{% set b = 2 %}{% include 'path/to/x' with {a:a} only %}{# in path/to/x a=1 and b does not exist #}
Rename variables in the with (can be combined with only):
twig{% set a = 1 %}{% include 'path/to/x' with {y:a} %} {# in path/to/x a=1 and y=1 #}{% include 'path/to/z' with {y:a} only %}{# in path/to/z y=1 and a does not exist #}
twig{% set a = 1 %}{% include 'path/to/x' with {y:a} %} {# in path/to/x a=1 and y=1 #}{% include 'path/to/z' with {y:a} only %}{# in path/to/z y=1 and a does not exist #}
Fundamental ERB for Front-End Development
Your comprehensive guide for ERB front-end view templates.
Comparing docs site builders: VuePress vs Starlight
How do these two frameworks measure up?
Comparing Heroku, Netlify, Vercel, and GitHub Pages for Node.js Projects
Running popular web-based CD tools against each other