/symfony-ux
Symfony UX frontend stack -- decision tree and orchestrator for choosing between Stimulus, Turbo, TwigComponent, LiveComponent, UX Icons, and UX Map. Use when the user is unsure which tool fits, wants to combine multiple UX packages, or asks a general frontend architecture
$ npx -y skills add smnandre/symfony-ux-skills --skill symfony-ux --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/symfony-ux
Context preview
The summary Claude sees to decide when to auto-load this skill.
Symfony UX frontend stack -- decision tree and orchestrator for choosing between Stimulus, Turbo, TwigComponent, LiveComponent, UX Icons, and UX Map. Use when the user is unsure which tool fits, wants to combine multiple UX packages, or asks a general frontend architecture
SKILL.md
symfony-ux.SKILL.mdname: symfony-ux
description: Symfony UX frontend stack -- decision tree and orchestrator for choosing between Stimulus, Turbo, TwigComponent, LiveComponent, UX Icons, and UX Map. Use when the user is unsure which tool fits, wants to combine multiple UX packages, or asks a general frontend architecture question in Symfony. Also trigger when the user asks "which UX package should I use", "how to make this interactive", "should I use Stimulus or LiveComponent", "how to structure my Symfony frontend", "what is the difference between Turbo and LiveComponent", "should this be a Frame or a LiveComponent", "how do these UX packages work together", "what is the Symfony way to do frontend". Do NOT trigger when the user clearly names a specific tool (stimulus, turbo, twig-component, live-component, ux-icons, ux-map) -- defer to the specialized skill instead.
license: MIT
metadata:
author: Simon Andre
email: smn.andre@gmail.com
url: https://smnandre.dev
version: "1.2.0"
Symfony UX
Modern frontend stack for Symfony. Build reactive UIs with minimal JavaScript using server-rendered HTML.
Symfony UX follows a progressive enhancement philosophy: start with plain HTML, add interactivity only where needed, and prefer server-side rendering over client-side JavaScript. Each tool solves a specific problem -- pick the simplest one that fits.
Decision Tree: Which Tool?
Need frontend interactivity?
|
+-- Pure JavaScript behavior (no server)?
| -> Stimulus
| (DOM manipulation, event handling, third-party libs)
|
+-- Navigation / partial page updates?
| -> Turbo
| +-- Full page AJAX -> Turbo Drive (automatic, zero config)
| +-- Single section update -> Turbo Frame
| +-- Multiple sections -> Turbo Stream
|
+-- Reusable UI component?
| |
| +-- Static (no live updates)?
| | -> TwigComponent
| | (props, blocks, computed properties)
| |
| +-- Dynamic (re-renders on interaction)?
| -> LiveComponent
| (data binding, actions, forms, real-time validation)
|
+-- Need icons?
| -> UX Icons
| (inline SVG from 200+ Iconify sets or local files)
|
+-- Need an interactive map?
| -> UX Map
| (Leaflet or Google Maps, markers, polygons, circles)
|
+-- Real-time (WebSocket/SSE)?
-> Turbo Stream + MercureThe tools compose naturally. A typical page uses Turbo Drive for navigation, Turbo Frames for partial sections, TwigComponents for reusable UI elements, LiveComponents for reactive forms/search, and Stimulus for client-side behavior that doesn't need a server round-trip.
Quick Comparison
| Feature | Stimulus | Turbo | TwigComponent | LiveComponent | |---------|----------|-------|---------------|---------------| | JavaScript required | Yes (minimal) | No | No | No | | Server re-render | No | Yes (page/frame) | No | Yes (AJAX) | | State management | JS only | URL/Server | Props (immutable) | LiveProp (mutable) | | Two-way binding | Manual | No | No | data-model | | Real-time capable | Manual | Yes (Streams+Mercure) | No | Yes (polling/emit) | | Lazy loading | Yes (stimulusFetch) | Yes (lazy frames) | No | Yes (defer/lazy) |
**UX Icons** and **UX Map** are utility packages that complement the tools above. Icons provides inline SVG rendering (local files + 200,000+ Iconify icons). Map provides interactive maps (Leaflet or Google Maps) with PHP-first configuration. Both work inside TwigComponents, LiveComponents, and Turbo Frames. Map also has a dedicated `ComponentWithMapTrait` for reactive maps in LiveComponents.
Installation
# All core packages
composer require symfony/ux-turbo symfony/stimulus-bundle \
symfony/ux-twig-component symfony/ux-live-component
# Individual
composer require symfony/stimulus-bundle # Stimulus
composer require symfony/ux-turbo # Turbo
composer require symfony/ux-twig-component # TwigComponent
composer require symfony/ux-live-component # LiveComponent (includes TwigComponent)
composer require symfony/ux-icons # UX Icons
composer require symfony/ux-map # UX Map (then add a renderer below)
composer require symfony/ux-leaflet-map # Leaflet renderer (free)
composer require symfony/ux-google-map # Google Maps renderer (requires API key)Common Patterns
Pattern 1: Static Component (TwigComponent)
Reusable UI with no interactivity. Use for buttons, cards, alerts, badges.
#[AsTwigComponent]
final class Alert
{
public string $type = 'info';
public string $message;
}{# templates/components/Alert.html.twig #}
<div class="alert alert-{{ type }}" {{ attributes }}>
{{ message }}
</div><twig:Alert type="success" message="Saved!" />
Pattern 2: Component + JS Behavior (TwigComponent + Stimulus)
Server-rendered component with client-side interactivity. Use when the interaction is purely cosmetic (toggling, animations, third-party JS libs) and doesn't need server data.
#[AsTwigComponent]
final class Dropdown
{
public string $label;
}{# templates/components/Dropdown.html.twig #}
<div data-controller="dropdown" {{ attributes }}>
<button data-action="click->dropdown#toggle">{{ label }}</button>
<div data-dropdown-target="menu" hidden>
{% block content %}{% endblock %}
</div>
</div>Pattern 3: Server-Reactive Component (LiveComponent)
Component that re-renders via AJAX on user input. Use for search boxes, filters, forms with real-time validation, anything that needs server data on every interaction.
#[AsLiveComponent]
final class SearchBox
{
use DefaultActionTrait;
#[LiveProp(writable: true, url: true)]
public string $query = '';
public function __construct(
private readonly ProductRepository $products,
) {}
public function getResults(): array
{
return $this->products->search($this->query);
}
}<div {{ attributes }}>
<input dataRead more
name: symfony-ux description: Symfony UX frontend stack -- decision tree and orchestrator for choosing between Stimulus, Turbo, TwigComponent, LiveComponent, UX Icons, and UX Map. Use when the user is unsure which tool fits, wants to combine multiple UX packages, or asks a general frontend architecture question in Symfony. Also trigger when the user asks "which UX package should I use", "how to make this interactive", "should I use Stimulus or LiveComponent", "how to structure my Symfony frontend", "what is the difference between Turbo and LiveComponent", "should this be a Frame or a LiveComponent", "how do these UX packages work together", "what is the Symfony way to do frontend". Do NOT trigger when the user clearly names a specific tool (stimulus, turbo, twig-component, live-component, ux-icons, ux-map) -- defer to the specialized skill instead. license: MIT metadata: author: Simon Andre email: smn.andre@gmail.com url: https://smnandre.dev version: "1.2.0"
Symfony UX
Modern frontend stack for Symfony. Build reactive UIs with minimal JavaScript using server-rendered HTML.
Symfony UX follows a progressive enhancement philosophy: start with plain HTML, add interactivity only where needed, and prefer server-side rendering over client-side JavaScript. Each tool solves a specific problem -- pick the simplest one that fits.
Decision Tree: Which Tool?
Need frontend interactivity?
|
+-- Pure JavaScript behavior (no server)?
| -> Stimulus
| (DOM manipulation, event handling, third-party libs)
|
+-- Navigation / partial page updates?
| -> Turbo
| +-- Full page AJAX -> Turbo Drive (automatic, zero config)
| +-- Single section update -> Turbo Frame
| +-- Multiple sections -> Turbo Stream
|
+-- Reusable UI component?
| |
| +-- Static (no live updates)?
| | -> TwigComponent
| | (props, blocks, computed properties)
| |
| +-- Dynamic (re-renders on interaction)?
| -> LiveComponent
| (data binding, actions, forms, real-time validation)
|
+-- Need icons?
| -> UX Icons
| (inline SVG from 200+ Iconify sets or local files)
|
+-- Need an interactive map?
| -> UX Map
| (Leaflet or Google Maps, markers, polygons, circles)
|
+-- Real-time (WebSocket/SSE)?
-> Turbo Stream + MercureThe tools compose naturally. A typical page uses Turbo Drive for navigation, Turbo Frames for partial sections, TwigComponents for reusable UI elements, LiveComponents for reactive forms/search, and Stimulus for client-side behavior that doesn't need a server round-trip.
Quick Comparison
| Feature | Stimulus | Turbo | TwigComponent | LiveComponent | |---------|----------|-------|---------------|---------------| | JavaScript required | Yes (minimal) | No | No | No | | Server re-render | No | Yes (page/frame) | No | Yes (AJAX) | | State management | JS only | URL/Server | Props (immutable) | LiveProp (mutable) | | Two-way binding | Manual | No | No | data-model | | Real-time capable | Manual | Yes (Streams+Mercure) | No | Yes (polling/emit) | | Lazy loading | Yes (stimulusFetch) | Yes (lazy frames) | No | Yes (defer/lazy) |
**UX Icons** and **UX Map** are utility packages that complement the tools above. Icons provides inline SVG rendering (local files + 200,000+ Iconify icons). Map provides interactive maps (Leaflet or Google Maps) with PHP-first configuration. Both work inside TwigComponents, LiveComponents, and Turbo Frames. Map also has a dedicated `ComponentWithMapTrait` for reactive maps in LiveComponents.
Installation
# All core packages
composer require symfony/ux-turbo symfony/stimulus-bundle \
symfony/ux-twig-component symfony/ux-live-component
# Individual
composer require symfony/stimulus-bundle # Stimulus
composer require symfony/ux-turbo # Turbo
composer require symfony/ux-twig-component # TwigComponent
composer require symfony/ux-live-component # LiveComponent (includes TwigComponent)
composer require symfony/ux-icons # UX Icons
composer require symfony/ux-map # UX Map (then add a renderer below)
composer require symfony/ux-leaflet-map # Leaflet renderer (free)
composer require symfony/ux-google-map # Google Maps renderer (requires API key)Common Patterns
Pattern 1: Static Component (TwigComponent)
Reusable UI with no interactivity. Use for buttons, cards, alerts, badges.
#[AsTwigComponent]
final class Alert
{
public string $type = 'info';
public string $message;
}{# templates/components/Alert.html.twig #}
<div class="alert alert-{{ type }}" {{ attributes }}>
{{ message }}
</div><twig:Alert type="success" message="Saved!" />
Pattern 2: Component + JS Behavior (TwigComponent + Stimulus)
Server-rendered component with client-side interactivity. Use when the interaction is purely cosmetic (toggling, animations, third-party JS libs) and doesn't need server data.
#[AsTwigComponent]
final class Dropdown
{
public string $label;
}{# templates/components/Dropdown.html.twig #}
<div data-controller="dropdown" {{ attributes }}>
<button data-action="click->dropdown#toggle">{{ label }}</button>
<div data-dropdown-target="menu" hidden>
{% block content %}{% endblock %}
</div>
</div>Pattern 3: Server-Reactive Component (LiveComponent)
Component that re-renders via AJAX on user input. Use for search boxes, filters, forms with real-time validation, anything that needs server data on every interaction.
#[AsLiveComponent]
final class SearchBox
{
use DefaultActionTrait;
#[LiveProp(writable: true, url: true)]
public string $query = '';
public function __construct(
private readonly ProductRepository $products,
) {}
public function getResults(): array
{
return $this->products->search($this->query);
}
}<div {{ attributes }}>
<input dataShowing the first part of this file.
AI agent skills for the Symfony UX frontend stack -- Stimulus, Turbo, TwigComponent, LiveComponent, UX Icons and UX Map. By Simon Andre
Repo: smnandre/symfony-ux-skills
Other skills on symfony-ux-skills.
- /live-component
Symfony UX LiveComponent for reactive server-rendered UI -- components that re-render via AJAX on user interaction, zero JavaScript required. Use when building live search, real-time filtering, dynamic forms, inline validation, dependent selects, auto-save, polling,
Open skill - /stimulus
Stimulus JS framework for Symfony UX -- client-side behavior via HTML data attributes, zero server round-trips. Use when creating controllers for DOM manipulation, handling click/input/submit events, managing targets and values, wiring outlets between controllers, wrapping
Open skill - /turbo
Hotwire Turbo for Symfony UX -- SPA-like speed with zero JavaScript. Covers Drive (navigation), Frames (partial page sections), and Streams (multi-target updates). Use when building ajax navigation, lazy-loaded sections, inline editing, pagination without reload, modals from the
Open skill - /twig-component
Symfony UX TwigComponent for reusable UI building blocks -- server-rendered components with PHP classes and Twig templates. Use when creating buttons, cards, alerts, badges, navbars, or any reusable UI element with props, blocks/slots, computed properties, or anonymous
Open skill - /ux-icons
Symfony UX Icons for rendering SVG icons in Twig templates. Supports 200,000+ Iconify icons (Lucide, Heroicons, Tabler, Material Design, etc.), local SVG files, and custom icon sets with aliases. Use when displaying icons, configuring icon defaults, importing or locking
Open skill - /ux-map
Symfony UX Map for interactive maps with Leaflet or Google Maps in Symfony. Covers markers, polygons, polylines, circles, info windows, and LiveComponent integration. Use when displaying maps, placing markers, drawing shapes or routes, handling map events, building store
Open skill

