Componentes Twig no Symfony: Construindo um Design System em PHP
Olá pessoas! Assim como um bom programador, estava em busca de conhecimento e recentemente participei de uma palestra dos meus colegas David e da Julia na IXC Soft sobre Design System — uma palestra incrível.
Para quem não conhece, um Design System é basicamente uma biblioteca de componentes reutilizáveis que mantém a consistência visual e funcional de uma aplicação. Pense em botões, alertas, modais e cards que você usa repetidamente — em vez de reescrever HTML e CSS toda vez, você cria componentes que podem ser chamados onde precisar. Isso facilita manutenção, garante consistência e acelera o desenvolvimento.
No entanto, uma curiosidade ficou na minha mente na parte de componentes. Foram citados os mais famosos frameworks como React e Vue.js, mas e PHP? Ficou para trás?
A Descoberta dos Twig Components
Na curiosidade — já que eu nunca tinha ouvido falar em desenvolver componentes HTML em PHP — pensei em reinventar essa roda usando Twig, um local onde você consegue gerenciar e gerar componentes de forma dinâmica. Mas pesquisando um pouco, percebi que cheguei meio atrasado.
O Twig (gerenciador de templates do Symfony) já possui um pacote chamado
symfony/ux-twig-component. A instalação é simples via Composer:
composer require symfony/ux-twig-component
Pronto! O pacote está instalado e pronto para uso. Para mais detalhes e recursos avançados, consulte a documentação oficial do Symfony UX Twig Components.
Criando Seu Primeiro Componente
Agora vem o ponto interessante: com o console do Symfony você pode criar um componente, por exemplo:
php bin/console make:twig-component Alert
Esse comando cria alguns arquivos no seu projeto. Vamos falar sobre eles:
src/Twig/Components/Alert.phptemplates/components/Alert.html.twig
Entendendo o Alert.php
Esse arquivo é a classe do componente, onde colocamos a lógica: funções, variáveis etc. Alguns pontos importantes:
- Variáveis públicas: todas podem ser usadas diretamente no template do componente
- Método construtor: não é
__construct, e simmount. Omounté chamado primeiro e funciona como um construtor ou um setUp
💡 Nota Importante
É um exemplo simples, mas funcional. Observe o default no switch — isso garante que
se alguém passar um tipo inválido (como "danger"), o sistema lançará uma exceção clara em vez de
renderizar um componente vazio. Sempre valide entradas!
Em produção, você poderia usar um Enum (PHP 8.1+) para os tipos ou criar constantes de classe, tornando o código ainda mais robusto.
Construindo o Template Alert.html.twig
Originalmente o arquivo do componente vem desta maneira:
<div{{ attributes }}>
<!-- component HTML -->
</div>
Depois de montar o HTML do componente usando um pouco de CSS e as variáveis públicas,
o meu arquivo Alert.html.twig ficou assim:
<div{{ attributes }}>
<style>
.alert-custom {
display: block;
padding: 14px 18px;
border-radius: 8px;
border: 2px solid {{ colorText }};
background: {{ colorBackground }};
color: {{ colorText }};
font-family: system-ui, sans-serif;
font-size: 0.95rem;
line-height: 1.4;
}
.alert-custom strong {
font-weight: 600;
margin-right: 4px;
}
</style>
<div class="alert-custom">
<strong>{{ title }}</strong> {{ description }}
</div>
</div>
⚠️ Importante sobre Estilização
CSS inline aqui é apenas didático! Em produção, use TailwindCSS, classes CSS externas
ou CSS Modules. Colocar <style> dentro do componente polui o HTML e dificulta manutenção.
Quanto à lógica, em aplicações reais você provavelmente buscaria dados de uma entidade, API ou serviço, em vez de hardcoded no componente. O objetivo aqui é mostrar a estrutura e possibilidades.
Configurando o Controller
Criei um controller básico só para rodar uma rota "Home":
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class HomeController extends AbstractController
{
#[Route('/', name: 'home')]
public function home(): Response
{
return $this->render('home/home.html.twig');
}
}
Usando o Componente no Template
Para chamar componentes Twig no template, existem duas formas:
<twig:Alert />
ou
{{ component('Alert') }}
A comunidade costuma usar o padrão <twig:Alert />, então mantive ele:
{% extends 'base.html.twig' %}
{% block body %}
<h1>Página inicial</h1>
{% set return = 'info' %}
{% if return == 'error' %}
<twig:Alert type="error" />
{% endif %}
{% if return == 'warning' %}
<twig:Alert type="warning" />
{% endif %}
{% if return == 'success' %}
<twig:Alert type="success" />
{% endif %}
{% if return == 'info' %}
<twig:Alert type="info" />
{% endif %}
{% endblock %}
Os 4 Tipos de Alertas Renderizados
Veja como cada tipo de alerta é renderizado no navegador:
Como Funciona na Prática
Se você é bom em lógica, já percebeu onde isso chega. Ao alterar o valor da variável definida em
{% set return = '' %}, o componente correspondente é chamado.
O valor passa para o type, que aciona o mount(), que chama a validação,
define os atributos e finalmente renderiza o componente com o resultado esperado.
🔍 Passando Variáveis
Falando um pouco mais sobre essa chamada do componente, você já deve ter percebido que a variável
type está sendo passada logo após <twig:Alert.
Isso é um padrão do componente.
Em outros casos, sem usar a função que valida o type, eu poderia ter passado todas as variantes dentro da chamada do componente, desta maneira:
<twig:Alert
title="Sucesso!"
description="Ação realizada com sucesso!"
colorBackground="#90EE90"
colorText="green"
/>
Casos de Uso Reais
Mas afinal, onde usar Twig Components no dia a dia? Aqui vão alguns exemplos práticos:
🎯 Aplicações Práticas
-
Sistema de Notificações: Exibir mensagens de feedback
após ações do usuário (cadastro, login, exclusão, etc). Em vez de repetir HTML em vários
templates, um simples
<twig:Alert type="success" />resolve. - Validação de Formulários: Mostrar erros de validação de forma consistente. Cada campo com erro pode renderizar um componente de alerta específico.
- Cards de Produtos/Notícias: Se você tem uma lista de produtos, cards de blog ou portfólio, componentes garantem que todos terão a mesma estrutura, facilitando mudanças futuras.
- Elementos de UI Reutilizáveis: Botões, badges, modais, tooltips — qualquer coisa que se repete na sua aplicação é candidata a virar componente.
- Dashboards e Relatórios: Componentes de gráficos, estatísticas e widgets que você reutiliza em diferentes páginas administrativas.
No meu caso, já estou pensando em usar isso no Gatepass (sistema de gestão de ingressos) para padronizar alertas de validação e cards de eventos. A manutenção fica muito mais fácil quando você altera em um lugar e reflete em todo o sistema.
Conclusão e Próximos Passos
Os Twig Components provam que PHP não ficou para trás quando o assunto é Design System e componentização. Com o Symfony, temos ferramentas poderosas para criar interfaces modulares e reutilizáveis, seguindo os mesmos princípios dos frameworks JavaScript modernos.
Este foi um overview prático focado no básico. Mas há muito mais a explorar, como:
- LiveComponents: Adicionar interatividade em tempo real sem JavaScript
- Computed Properties: Propriedades calculadas dinamicamente
- Slots: Passar conteúdo HTML customizado para componentes
- PreMount/PostMount Hooks: Controlar o ciclo de vida dos componentes
📚 Recursos Adicionais
- 📖 Documentação Oficial do Symfony UX Twig Components
- 🎬 SymfonyCasts - Twig Components Tutorial
- 💡 Symfony UX Initiative - Modernizando a experiência do usuário com Symfony
Espero que tenham gostado do conteúdo. Caso queiram discutir sobre, não hesitem em comentar no post do LinkedIn. Até mais!