Twig templates
Twig is Blade's cousin / JSX's distant relative. Escapes by default, extends layouts, and lives under
templates/.
Layout + page
twig
{# templates/base.html.twig #}
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}App{% endblock %}</title>
{% block stylesheets %}{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
{% block javascripts %}{% endblock %}
</body>
</html>twig
{# templates/posts/index.html.twig #}
{% extends 'base.html.twig' %}
{% block title %}Posts{% endblock %}
{% block body %}
<h1>Posts</h1>
<ul>
{% for post in posts %}
<li>
<a href="{{ path('app_posts_show', { id: post.id }) }}">
{{ post.title }}
</a>
</li>
{% else %}
<li>No posts yet.</li>
{% endfor %}
</ul>
{% endblock %}Comments for the code above:
{{ post.title }}is escaped HTML - like Blade{{ }}or React text children{% … %}is logic/tags;{{ … }}printspath('route_name', {…})builds URLs from named routes
Escaping vs raw
twig
{{ userBio }} {# escaped - default, good #}
{{ userBio|raw }} {# dangerous if user-controlled #}Same rule as Blade {!! !!} - only raw when you trust the content.
Includes & embeds
twig
{% include 'partials/_nav.html.twig' %}Macros / embeds exist for reusable chunks. Start with include; grow when it hurts.
Forms in Twig
When you use the Form component (next chapters), you'll see:
twig
{{ form_start(form) }}
{{ form_row(form.title) }}
{{ form_row(form.body) }}
<button>Save</button>
{{ form_end(form) }}That's CSRF + labels + errors wired for you.
FE mental map
| Vue / React / Blade | Twig |
|---|---|
| layout component | {% extends %} |
v-for / .map | {% for %} |
{{ }} text | {{ }} (escaped) |
v-if | {% if %} |
| named routes helper | path() / url() |
Next: how CSS/JS land in the page without inventing a second build religion.
Best,
-- ł.