$npx -y skills add smnandre/symfony-ux-skills --skill symfony-uxSymfony 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 questi
| 1 | # Symfony UX |
| 2 | |
| 3 | Modern frontend stack for Symfony. Build reactive UIs with minimal JavaScript using server-rendered HTML. |
| 4 | |
| 5 | 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. |
| 6 | |
| 7 | ## Decision Tree: Which Tool? |
| 8 | |
| 9 | ``` |
| 10 | Need frontend interactivity? |
| 11 | | |
| 12 | +-- Pure JavaScript behavior (no server)? |
| 13 | | -> Stimulus |
| 14 | | (DOM manipulation, event handling, third-party libs) |
| 15 | | |
| 16 | +-- Navigation / partial page updates? |
| 17 | | -> Turbo |
| 18 | | +-- Full page AJAX -> Turbo Drive (automatic, zero config) |
| 19 | | +-- Single section update -> Turbo Frame |
| 20 | | +-- Multiple sections -> Turbo Stream |
| 21 | | |
| 22 | +-- Reusable UI component? |
| 23 | | | |
| 24 | | +-- Static (no live updates)? |
| 25 | | | -> TwigComponent |
| 26 | | | (props, blocks, computed properties) |
| 27 | | | |
| 28 | | +-- Dynamic (re-renders on interaction)? |
| 29 | | -> LiveComponent |
| 30 | | (data binding, actions, forms, real-time validation) |
| 31 | | |
| 32 | +-- Need icons? |
| 33 | | -> UX Icons |
| 34 | | (inline SVG from 200+ Iconify sets or local files) |
| 35 | | |
| 36 | +-- Need an interactive map? |
| 37 | | -> UX Map |
| 38 | | (Leaflet or Google Maps, markers, polygons, circles) |
| 39 | | |
| 40 | +-- Real-time (WebSocket/SSE)? |
| 41 | -> Turbo Stream + Mercure |
| 42 | ``` |
| 43 | |
| 44 | The 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. |
| 45 | |
| 46 | ## Quick Comparison |
| 47 | |
| 48 | | Feature | Stimulus | Turbo | TwigComponent | LiveComponent | |
| 49 | |---------|----------|-------|---------------|---------------| |
| 50 | | JavaScript required | Yes (minimal) | No | No | No | |
| 51 | | Server re-render | No | Yes (page/frame) | No | Yes (AJAX) | |
| 52 | | State management | JS only | URL/Server | Props (immutable) | LiveProp (mutable) | |
| 53 | | Two-way binding | Manual | No | No | data-model | |
| 54 | | Real-time capable | Manual | Yes (Streams+Mercure) | No | Yes (polling/emit) | |
| 55 | | Lazy loading | Yes (stimulusFetch) | Yes (lazy frames) | No | Yes (defer/lazy) | |
| 56 | |
| 57 | **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. |
| 58 | |
| 59 | ## Installation |
| 60 | |
| 61 | ```bash |
| 62 | # All core packages |
| 63 | composer require symfony/ux-turbo symfony/stimulus-bundle \ |
| 64 | symfony/ux-twig-component symfony/ux-live-component |
| 65 | |
| 66 | # Individual |
| 67 | composer require symfony/stimulus-bundle # Stimulus |
| 68 | composer require symfony/ux-turbo # Turbo |
| 69 | composer require symfony/ux-twig-component # TwigComponent |
| 70 | composer require symfony/ux-live-component # LiveComponent (includes TwigComponent) |
| 71 | composer require symfony/ux-icons # UX Icons |
| 72 | composer require symfony/ux-map # UX Map (then add a renderer below) |
| 73 | composer require symfony/ux-leaflet-map # Leaflet renderer (free) |
| 74 | composer require symfony/ux-google-map # Google Maps renderer (requires API key) |
| 75 | ``` |
| 76 | |
| 77 | ## Common Patterns |
| 78 | |
| 79 | ### Pattern 1: Static Component (TwigComponent) |
| 80 | |
| 81 | Reusable UI with no interactivity. Use for buttons, cards, alerts, badges. |
| 82 | |
| 83 | ```php |
| 84 | #[AsTwigComponent] |
| 85 | final class Alert |
| 86 | { |
| 87 | public string $type = 'info'; |
| 88 | public string $message; |
| 89 | } |
| 90 | ``` |
| 91 | |
| 92 | ```twig |
| 93 | {# templates/components/Alert.html.twig #} |
| 94 | <div class="alert alert-{{ type }}" {{ attributes }}> |
| 95 | {{ message }} |
| 96 | </div> |
| 97 | ``` |
| 98 | |
| 99 | ```twig |
| 100 | <twig:Alert type="success" message="Saved!" /> |
| 101 | ``` |
| 102 | |
| 103 | ### Pattern 2: Component + JS Behavior (TwigComponent + Stimulus) |
| 104 | |
| 105 | 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. |
| 106 | |
| 107 | ``` |