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().

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.