Symfony Twig Components: Getting Started

In previous topics, we explored JavaScript Stimulus components. Now we'll learn server-side Twig Components.

Twig Components let you create reusable UI pieces by pairing a PHP class with a Twig template. Think of them as custom HTML tags for your application.

Why Use Twig Components?

  • Reusability — Define once, use everywhere. No more copying the same HTML structure across templates.
  • Encapsulation — Logic lives in the PHP class, presentation in the template. Each component is self-contained.
  • Type safety — Public properties can be typed, giving you IDE autocompletion and catching errors early.
  • Cleaner templates{{ component('Alert', { type: 'error', message: 'Failed' }) }} is more readable.
  • Refactoring confidence — Change a component's internals without hunting through every template that uses it.

Installation

Open your project, click Tools -> Composer packages, add the package:

symfony/ux-twig-component.

Generate scripts, then install the recipe manually by Command Prompt or PowerShell:

php bin/console app:recipes:install symfony/ux-twig-component

The recipe does minimal setup:

  1. Registers the bundle in config/bundles.php
  2. Creates the configuration file config/packages/twig_component.yaml which typically maps a namespace to your components directory, i.e. templates/components/ by default.

Your First Component

Every component has two parts: a PHP class that holds the data, and a Twig template that renders it.

The PHP class:

Create a Custom File with:

  • File Name - Alert.php
  • Include Common Files - DISABLE IT. It is not applicable.
  • Caption - NOT applicable.
  • Path - Set the path as src/Twig/Components.
  • Content - Enter your whole class, note that you should use the special placeholder {ProjectNamespace} as your namespace.
<?php
// src/Twig/Components/Alert.php

namespace {ProjectNamespace}\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
class Alert
{
    public string $type = 'info';
    public string $message;
}

The template:

Create a Custom File with:

  • File Name - Alert.html.twig
  • Include Common Files - DISABLE IT. It is not applicable.
  • Caption - NOT applicable.
  • Path - Set the path as templates/components.
  • Content - Enter your template for the component, e.g.
{# templates/components/Alert.html.twig #}
<div class="alert alert-{{ type }}">
    {{ message }}
</div>

Using it:

{{ component('Alert', { type: 'success', message: 'Saved!' }) }}
{{ component('Alert', { type: 'danger', message: 'Something went wrong.' }) }}

Public properties on the class become attributes you pass when using the component.

Adding Content

To include HTML content in a component, pass it as a property:

<?php
// src/Twig/Components/Card.php

namespace {ProjectNamespace}\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
class Card
{
    public string $title;
    public string $content = '';
}
{# templates/components/Card.html.twig #}
<div class="card">
    <div class="card-header">{{ title }}</div>
    <div class="card-body">
        {{ content|raw }}
    </div>
</div>

Note: |raw tells Twig to output the content without escaping.

Using it:

{{ component('Card', { title: 'Welcome', content: '<p>Any HTML goes here.</p>' }) }}

Computed Properties

Add methods to your class and call them from the template:

<?php

namespace {ProjectNamespace}\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
class UserBadge
{
    public string $firstName;
    public string $lastName;
    
    public function getFullName(): string
    {
        return $this->firstName . ' ' . $this->lastName;
    }
}
<span class="badge">{{ this.fullName }}</span>

Access computed properties through this.fullName, which calls getFullName().

Syntax Limitations

PHPMaker supports the function syntax only:

{{ component('Name', { prop: 'value' }) }}

The <twig:Name ...> and {% component 'Name' ... %}{% endcomponent %} syntaxes are not supported:

Learn More

That covers the basics. Once you're comfortable, you can explore passing extra HTML attributes, dependency injection, PreMount hooks, and anonymous components.

Read Symfony UX Twig Components.