Symfony Twig Components¶
Added in version 12.0.
Twig Components is a Symfony UX bundle allowing to use components in Twig template, inspired by HTML components. It aims to replace Twig macros.
It also enables a cleaner integration with a Vue.js-like syntax, making components easier to maintain and review compared to the legacy macro-based integration.
The following components are available:
Usage¶
Twig components support various integration modes. We recommend using the Component HTML Syntax.
Component HTML Syntax¶
<twig:Alert title="My alert title" messages="My message" />
This syntax resembles modern frontend frameworks.
To pass dynamic values such as variables, booleans, or arrays, prefix the prop name with : and use a Twig expression:
<twig:Alert title="Overridden title" :messages="['Message 1', 'Message 2']" type="danger" :important="true">
<twig:block name="title">
<h4 class="alert-title">
Custom title block
</h4>
{{ parent() }} {# Renders the parent content — here: "Overridden title" #}
</twig:block>
</twig:Alert>
Most components also support a default content block. To inject content into it, place your markup directly inside the <twig:xx> tag:
<twig:Alert:Danger>
<twig:block name="title">
<h2 class="alert-title">
Custom title block
</h2>
</twig:block>
<div>
My alert content
</div>
</twig:Alert:Danger>
Creating a Component¶
A Twig component consists of two parts: a PHP class that declares the props and logic, and a Twig template that defines the markup.
The PHP Class¶
Create a class under src/Twig/Components/ and annotate it with #[AsTwigComponent].
By default, Public properties become the component’s props and are automatically available as variables in the template.
Public methods are also accessible from the template via the special this variable.
<?php
namespace Twig\Components;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(name: 'MyComponent', template: 'twig_components/MyComponent.html.twig')]
class MyComponent
{
public string $title = '';
public bool $important = false;
public function getComputedClass(): string
{
return $this->important ? 'text-bold' : '';
}
}
The name parameter sets the tag name used in templates (<twig:MyComponent />). If omitted, it is derived from the class namespace relative to Twig\Components.
The template parameter is also optional. If omitted, Symfony derives the template path from the class namespace, resolved under templates/twig_components/.
Note
For components with multiple variants (e.g., Alert:Success, Alert:Danger), the recommended pattern is to extract shared props and logic into an abstract base class, then create lightweight variant classes that extend it and override the relevant defaults. See src/Twig/Components/Alert/ (Github) for a real-world example.
The Twig Template¶
Place templates under templates/twig_components/. Props are available directly as template variables. The component object itself is accessible via this, which is useful for calling methods:
<div class="{{ this.computedClass }}">
{% block title %}
{% if title|length %}
<h4>{{ title }}</h4>
{% endif %}
{% endblock %}
{% block content %}{% endblock %}
</div>
Define {% block %} sections for any part of the markup that consumers may need to override.
The {% block content %} block is special: any markup placed directly inside the component tag (without an explicit <twig:block>) is injected into it automatically:
<twig:Alert>This text is injected into the content block.</twig:Alert>
Variants¶
Variant components share a base class and, typically, the same template. The class name determines the component tag name: a class Twig\Components\Alert\Danger automatically resolves to the tag <twig:Alert:Danger>.
<?php
namespace Twig\Components\Alert;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: 'twig_components/Alert/Info.html.twig')]
final class Danger extends AbstractAlert
{
public string $type = 'danger';
}
The template parameter is specified explicitly here because all Alert variants share a single template file (twig_components/Alert/Info.html.twig).
Testing¶
Two levels of tests are recommended:
Unit tests: instantiate the PHP class directly and assert prop defaults and method return values. No GLPI environment needed.
Rendering tests: render a Twig string using
TemplateRenderer::getInstance()->renderFromStringTemplate()and assert the resulting HTML. These extendGLPITestCase.
Tests live in tests/functional/Twig/Components/ (GitHub). See AlertTest.php and AlertRenderingTest.php for examples.
Debugging¶
To list all registered components and their resolved template paths, run:
bin/console symfony:debug:twig-component
# Using Makefile
make console c='symfony:debug:twig-component'
