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

Symfony Documentation

<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>
Example with custom twig block

Creating a Component

Symfony Documentation

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 extend GLPITestCase.

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'

Creative Commons License