Open-source project
symfony/ux avatar
symfony/ux

Symfony UX: a JavaScript ecosystem for a PHP framework

Symfony UX initiative: a JavaScript ecosystem for Symfony

1,081 stars443 forksPHPMIT

At a glance

What is it?
Symfony UX is an initiative and a set of libraries that fold JavaScript tools into a Symfony application, so a chart written with Chart.js is built in PHP and the JavaScript is handled for you. The packages lean on Stimulus, work with AssetMapper or Webpack Encore, and hold their shipped CSS and JavaScript to a Baseline browser target.
Who is it for?
Adopt Symfony UX if you build on Symfony and you want JavaScript behaviour without hand-wiring bundlers, controllers and asset pipelines for each library. Do not adopt it if your application is not on Symfony, and do not expect the packages to be a general JavaScript toolkit, since they exist to make one specific library usable from PHP.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • symfony/ux1,081 ★ · -1
Star history
Repository2026-10-202026-11-07
symfony/ux1.1k1.1k

-1 Stars in the last 18 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

An initiative first, a set of libraries second

The README describes Symfony UX as an initiative and set of libraries that integrate JavaScript tools into your application, and it is worth taking the word initiative seriously.

The example that explains the whole idea is short. You want to render a chart with Chart.js. You use UX Chart.js to build the chart in PHP, and the JavaScript is handled for you automatically. The line that follows is the thesis: that is Symfony UX.

So the packages are adapters. Each one takes a JavaScript library that would otherwise need a bundler entry point, a Stimulus controller, a template and a mount point, and turns it into a PHP API, a Twig component or a form type. That is a narrow job, and doing it dozens of times is a real saving.

The ask at the end of the README is for more of them. The text asks what other packages could be created, offering a library that automatically adds an input mask to the text fields of your Symfony forms as an example, and the general rule is that anything you do in JavaScript could be done streamlined as a UX package.

The official demo at ux.symfony.com is the fastest way to judge the ecosystem, and the list of UX packages with their documentation is the reference for what already exists.

Stimulus underneath, two asset pipelines on top

Symfony UX leverages Stimulus for JavaScript, and it can integrate with AssetMapper or with Webpack Encore, the latter with the help of Stimulus Bridge.

That choice of two build paths is the practical detail. AssetMapper is the modern Symfony default, where the asset map is derived from the source tree with no bundler at all, and Webpack Encore is the older pipeline that many existing applications still have. A package that works with both is a package that does not force a migration, and that is why the packages are JavaScript libraries with a PHP face rather than a bundler plugin.

Stimulus is the other half of the answer, and it is doing the work that most small integrations get wrong. Stimulus connects behaviour to markup through controllers, so the JavaScript for a UX package is a controller that attaches to a data attribute rather than a script that has to find an element and initialise it. That is also why the packages work with a server-rendered page without any client-side application shell.

The consequence for a user is that the frontend story stays in the hands of the framework. You render a component, the component renders the markup, the Stimulus controller attaches, and the JavaScript asset is shipped by whichever pipeline you use. There is no separate build step per package, and there is no node_modules directory to maintain for a chart.

Baseline is a constraint the packages agree to

The most consequential technical policy in the README is about browser support, and it is easy to skim past.

The JavaScript and CSS shipped by Symfony UX packages stay within Baseline Widely available, meaning every major browser has supported these features for at least 30 months. A package can state its own requirement, and Notify currently does.

That is a real constraint rather than a slogan, and it is a good one. A library that ships modern syntax to a page that has to work in an organisation's older browsers is a support incident, and a Baseline target turns that into a build-time check. The badge in the README is even a dynamic one, reading the baseline setting out of the package.json rather than hard-coding it.

The exception mechanism is the interesting part. A package can state its own requirement, so a package whose whole purpose depends on a newer feature can opt out, and Notify is the example given. That is the difference between a policy and a prohibition, and it is why the constraint is workable in practice.

For an adopter, the practical check is on the package you want rather than on the ecosystem as a whole, because the exception means the ecosystem baseline is a floor and not a ceiling.

The monorepo behind the packages

The repository is a large workspace, and its layout is a good map of how the ecosystem is put together.

The src/ directory holds the packages themselves, and the pnpm workspaces are configured to pick up the asset directories inside them, src/*/assets and src/*/src/Bridge/*/assets. The second pattern is the interesting one, since it is where a package that bridges to a JavaScript library keeps its own front end.

The JavaScript side of the monorepo is modern and deliberately varied. The tooling is oxlint and oxfmt for linting and formatting, with a separate check_baseline script that reads the baseline configuration, and a script to update the tooling dependencies. Tests run under vitest with a browser tier driven by Playwright, and a separate unit tier for the bin/ directory. There is a pnpm-lock.yaml, a babel.config.js and a biome.json, plus TypeScript configurations for the workspace and for the packages. On the PHP side there are php-cs-fixer and twig-cs-fixer configurations, a .doctor-rst.yaml for the documentation, and a composer.json.

The scripts show the shape of a release. The build runs the map package first, then a sync step, then the rest, and the test scripts run with a workspace concurrency of one, which is what a suite that compiles browser bundles tends to need.

There is also a docs directory of its own, ux.symfony.com/, a MAINTAINERS.md, an UPGRADE-3.0.md for the 3.x transition, a release.sh and a splitsh.json, which is the tool Symfony uses to push changes into the split repositories where each package is published.

Sponsorship, and the realtime story

The sponsor section points at Mercure.rocks, and it is worth reading because it explains what the realtime packages in the ecosystem are for.

Mercure.rocks provides a realtime API service that is tightly integrated with Symfony. The README describes the combination: create user interfaces that update live with UX Turbo, send notifications with the Notifier component, expose asynchronous APIs with API Platform, and create the lower level pieces with the Mercure component. The service maintains and scales the complex infrastructure, and sponsoring the project helps pay for that maintenance.

That is a coherent story, because Mercure is the transport that the Turbo and Notifier packages sit on, and a hosted version of it is a reasonable thing for a team to want rather than run.

For the ecosystem as a whole, the ask is broader. The README asks what other packages could be created and invites anyone to propose one, and the contributing guide is linked at the end. The repository also carries an AGENTS.md, a CLAUDE.md and a .agents/ directory, which is the current convention for a project that wants its conventions readable by tooling as well as by contributors.

Where Symfony UX is the wrong choice

The first wrong-tool case is a project that is not on Symfony. These packages are PHP implementations of JavaScript libraries, delivered as Symfony bundles and Twig components, and they assume the framework's conventions for forms, rendering and the asset pipeline. There is no version of this for a Laravel or a Django application, and there is not going to be one, because the value is in the integration with the framework rather than in the JavaScript itself.

The second is a team whose frontend is a single-page application. Stimulus and AssetMapper are built for server-rendered pages with progressive enhancement, and a project that ships its own bundle and hydrates the whole page is not what these packages are for. The JavaScript library inside is reusable, but the UX package around it is not.

The third is a project that has already solved the integration. A team that has a build step, a component library and a set of conventions for attaching behaviour to markup has no use for an adapter, and adding one is a second way to do the same thing.

The fourth is a project that needs the newest version of a JavaScript library. The packages pin versions, they hold themselves to a browser Baseline, and a package that needs a feature outside that Baseline has to state a higher requirement. A team that lives on the bleeding edge of a library will spend more time fighting the pin than using the adapter.

Editorial conclusion

Adopt Symfony UX if you build on Symfony and you want JavaScript behaviour without hand-wiring bundlers, controllers and asset pipelines for each library. Do not adopt it if your application is not on Symfony, and do not expect the packages to be a general JavaScript toolkit, since they exist to make one specific library usable from PHP. Before you start, check the browser Baseline requirement of the package you want, because a package can state its own requirement and Notify already does, and read the upgrade notes if you are moving to the 3.x line, since the repository carries a dedicated document for that change.

Frequently asked questions

What is Symfony UX?

An initiative and a set of libraries that integrate JavaScript tools into a Symfony application. The README's example is a chart built with Chart.js using the UX Chart.js package, where the chart is built in PHP and the JavaScript is handled for you automatically.

Which build tools does Symfony UX work with?

It leverages Stimulus for JavaScript and can integrate with AssetMapper or with Webpack Encore, the latter with the help of Stimulus Bridge, so a package works whichever of the two asset pipelines the application already uses.

What browser support do the Symfony UX packages target?

The JavaScript and CSS shipped by the packages stay within Baseline Widely available, meaning every major browser has supported those features for at least 30 months. A package can state its own requirement, and Notify currently does.

How does the Symfony UX repository build and test its packages?

It is a pnpm workspace whose workspaces are the asset directories inside src/* and src/*/src/Bridge/*/assets. The build runs the map package first and then a sync step, the tests run under vitest with a browser tier driven by Playwright, and linting and formatting use oxlint and oxfmt with a separate baseline check script.

What licence does Symfony UX use and how often does it release?

MIT, with the LICENSE file at the repository root, and the current default branch is 3.x. The most recent release is v3.6.0, dated 2026-10-13, with v3.5.0 and v3.5.1 both on 2026-09-19, and the last push was on 2026-10-15.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. symfony/ux on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/symfony-ux.svg)](https://hysenlabs.com/projects/symfony-ux)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/symfony-ux.svg)](https://hysenlabs.com/projects/symfony-ux)

Was this useful?