Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ux React Laravel Package

symfony/ux-react

Official Symfony UX React integration lets you render React components directly from Twig, pass props, and mount interactive UI inside Symfony pages. It pairs with Webpack Encore for asset building, making React easy to add to traditional server-rendered Symfony applications.

View on GitHub
Deep Wiki
Context7

Getting Started

symfony/ux-react is a Symfony UX bundle, not a Laravel package. It has no ServiceProvider for Laravel's package discovery, no config/ux_react.php, and its whole surface area is Twig (a ReactComponent Twig component, a react_component() function) plus AssetMapper/Webpack Encore integration. So for a Laravel developer the first decision is not "how do I install it" but "should I be here at all."

  • If you are building a Laravel app: stop. Use laravel/react-starter-kit + Vite, or inertiajs/inertia-laravel if you want server-driven props. You get typing-free @vite, HMR out of the box, and Blade instead of Twig. Everything ux-react does for Symfony, Inertia does for Laravel with a fraction of the friction.
  • If you are a Laravel dev working in an existing Symfony codebase (contract work, a monorepo, a migration), this is the package you'll be handed. Start with:
    1. composer require symfony/ux-react
    2. Pick your asset strategy — AssetMapper (importmap.php, no Node) or Webpack Encore (encore dev-server). They are not mixed.
    3. AssetMapper: php bin/console importmap:require react react-dom. Encore: npm i react react-dom.
    4. Drop a component in assets/react/controllers/Hello.jsx and render it: <twig:ReactComponent component="Hello" props="{{ { name: 'world' } }}" />

The first thing to look at is assets/controllers.json (AssetMapper) or the registerReactControllerComponents(...) call in assets/bootstrap.js (Encore) — that is the registration boundary for every component you'll ever render. If a component "doesn't exist," the answer is almost always there.

For v3.6.0 specifically: nothing changes here. The release is a README wording fix, a dev-tooling bump, and a compatibility fix for symfony/asset-mapper 8.2+. If your project sat pinned on asset-mapper 8.1 because of the conflict, 3.6.0 unblocks the upgrade.

Implementation Patterns

Twig-component rendering (the normal path). Each <twig:ReactComponent> is an independent React root. Props come from Twig and are JSON-injected, so your controllers are pure functions of server data. The idiomatic pattern is "thin component, fat server": compute the payload in PHP, serialize to a plain array, render. Do not try to lift state out of React and back into Twig except via a full page reload.

Prop serialization is your real integration layer. Pass DTOs flattened with Symfony's Serializer ($serializer->normalize($dto, 'json')) rather than entities. If you find yourself wanting |raw or |json_encode in the props expression, you've got a serialization bug upstream — fix it there, because the failure mode is a silent [object Object] or an uncaught JSON parse, not a helpful exception.

Multi-root pages. You'll often have three or four components on one page (a filter bar, a data table, a modal). They cannot share React context. Standard workarounds: (a) initialize a global store (Zustand/Redux) from a single bootstrapped prop, (b) use browser events/CustomEvent between roots, or (c) collapse them into one root component and let React own the whole section. Pattern (c) ages best; pattern (a) is the pragmatic first step.

Code splitting and lazy loading. React.lazy(() => import('./Heavy')) works, but only if your bundler emits a real chunk. With Encore this is transparent. With AssetMapper you need the dynamic import to resolve through the importmap (add the target as an importmap entry), otherwise you get a runtime Failed to fetch dynamically imported module that only reproduces in prod after importmap:install.

Interop with the rest of Symfony UX. Components are usually mounted from a Stimulus controller or a Turbo Frame. Two rules: mount on connect() and unmount on disconnect() (Turbo will cache and restore DOM), and treat every Turbo navigation as a fresh mount — do not cache React state across frames unless you deliberately hoist it. If you're also using ux-live/LiveComponents, keep them out of the React subtree; hydration conflicts there are painful to debug.

What to borrow for Laravel. Even if you never install this, two ideas transfer: server-normalized props as the contract (mirror it with Inertia's ->through() or API Resources), and per-root mounting with explicit unmount (mirror it in any Blade + createRoot you hand-roll).

Gotchas and Tips

  • AssetMapper 8.2 was broken until 3.6.0. If you saw importmap resolution failures or a composer conflict against symfony/asset-mapper >=8.2, upgrade ux-react to 3.6.0 rather than downgrading asset-mapper. The other two changelog entries (README version placeholder, tooling deps) are non-events — no runtime code, no API surface, no deprecations.
  • No HMR on AssetMapper. Encore's dev-server gives you React Fast Refresh; AssetMapper gives you reload-on-change at best. If DX matters more than dropping Node, pick Encore. This is the single biggest fork in the road and it's not reversible cheaply.
  • Component name resolution is silent. component="hello" vs Hello, missing .jsx in the glob, or a file outside assets/react/controllers produces a client-side "component not found" with no server error. Debug server-side with bin/console debug:twig to confirm the Twig component is registered, then verify the glob root.
  • StrictMode double-invokes effects in dev. Any fetch-on-mount will fire twice and look like a server bug. It isn't — don't "fix" it by guarding with a module-level flag.
  • Props must survive JSON.stringify. DateTime, entities with circular refs, and closures all fail here, and Symfony's error surface is unhelpful. The 3.x default json_encode flags also mean float precision and NAN quietly become null.
  • React version is your problem, not the bundle's. The package doesn't pin React; if you're on React 19 with an older Encore/Babel preset you'll get confusing jsx-dev-runtime resolution errors. Pin React in package.json and check peer deps before blaming the bundle.
  • Extension point when you outgrow it: the Twig component is a thin wrapper around a renderer service. If you need SSR-ish output or custom prop transforms, decorate the renderer in services.yaml rather than forking — this is the one place the Symfony DI approach genuinely beats Laravel's facade-centric style.
  • Debugging checklist, in order: importmap:audit (AssetMapper) or encore dev-server output → browser console for the component-name miss → debug:twig for registration → then the props payload. Nine times out of ten the bug is step two or four, not the bundle.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json
refinery29/php-cs-fixer-config
hotmeteor/eco-env
mvaliolahi/hydrate
wearede/tbcpay-php
parsnick/steak
thibaud-dauce/mattermost-php
multilinguals/apollo-client
antaresbr/collection
kr0lik/phpstan-rules