Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Symfony UX

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

Hey friends! I sure am glad you're here for part 1 of our 2 part Symfony UX series.

HTML Build on the Server or in JavaScript

But what is this Symfony UX thing anyways? That requires... a short - and I promise thrilling - history lesson. Until a few years ago, the web worked one way: your server - like our Symfony app - created HTML and sent it to the user. Then, we usually sprinkled some JavaScript on top.

Then, frontend frameworks came along with a totally new paradigm where your server returns JSON and the HTML is built on the client side in JavaScript. Taken to the extreme, you get single page applications.

And so, it seemed that the world was destined to keep moving in this direction: to use frontend frameworks to generate HTML. After all, isn't the user experience of a single page app way better? With its lack of page refreshes and instant updates?

Hello Hotwire

But a storm was growing - a movement in the other direction. One, that's all about doing what we did 5 years ago: generating HTML on the server.

This exploded in 2020 when DHH and company - creator of Ruby on Rails and Basecamp - built a new email service entirely with server-side generated HTML. Their claim was bold: that they could get a single page application experience by building a traditional app.

They called the idea Hotwire. Symfony UX is built on top of this concept.

Hotwire: Stimulus & Turbo

Ok: so what does this mean for us? Having a beautiful & interactive user interface requires two things. First, we need a way to write professional JavaScript... not 1000 line long jQuery files, or one-off scripts. And we need that JavaScript to work... even if we load some HTML via Ajax. That's a classic problem with JavaScript: behavior isn't necessarily applied to HTML elements that arrive on the page later.

This is all solved with Stimulus: a tiny JavaScript library and the topic of this tutorial.

The second part of a rich user interface is being able to avoid full page refreshes. That's handled by Turbo: the topic of the next tutorial.

Put Stimulus and Turbo together and suddenly you can write clean JavaScript that always works and have a site where every link click and form submit loads via Ajax. So basically: the single page application experience... without the hassle of building a single page application.

And if you're wondering: does this kill frontend frameworks like React or Vue? Nope! Though, you'll probably use them less, if ever. Later in the tutorial we'll render a React component inside of Stimulus and talk about when and why you might do that.

Project Setup

So... let's get this party started! This stuff is super fun so I recommend coding along with me. Download the course code from this page and unzip it. After you do, you'll find a start/ directory with the same code that you see here. Check out the README.md file for all the details you'll need to get the project running. This is a tutorial about JavaScript, but we're using a fully-featured Symfony app with a database.

The last step in the README will be to find a terminal, move into the project and start up the flux capacitor by running:

symfony serve -d

Don't worry: I programmed the time machine to not let us go back to 2020. This starts a local web server in the background. To see the site, we can run:

symfony open:local

Or, if you're less lazy, go to and say hello to... MVP office supplies! Our office furniture startup for other startups that embrace the minimum viable product mentality. All of our products are guaranteed to be barely viable at best.

This is the same project we built in our Vue tutorial if you want to compare them.

Right now, the site is styled but it has absolutely zero JavaScript. It's a completely traditional app with full page reloads. Adding things to the cart like this is done by submitting a normal, boring form.

Even the CSS itself is just a static file that lives in public/styles/: it's not being processed in any way.

So next: let's install Webpack Encore and use it to get a basic JavaScript and CSS setup that will form the baseline for using Stimulus.

Leave a comment!

Login or Register to join the conversation

I was rewatching that course as a refresher, and halfway into it, I had the great idea of searching for a Stimulus plugin for PhpStorm. And guess what... There is one.

I strongly recommend anyone doing this course to install it. It makes it so much easier to use Stimulus. I would also recommend Ryan or the SymfonyCast team to tell us about things like that when recording a course.


1 Reply

Hey Julien,

Could you share the exact plugin name for PhpStrom? It would help people to search it easier. :) But I agree, it's worth to be mentioned in the tutorial. And we usually do suggest some useful plugins or any. We will keep it in mind for further Stimulus-related tutorials.



Hey Victor,

The plugin name is "Stimulus" by anstarovoyt. It works pretty well.

My guess is that the plugin might not I've been available at the time of recording this course.



Hey @julien_bonnier!

Wow, yea - you're right, I had never heard of it! I've just installed it - but it doesn't look like there's any info about what it DOES. What does it do that you've noticed and like?



Hey Ryan,

Well first off, it allows PhpStorm to understand Stimulus code. So it will not complain about this.someValue if you have static values = { some: String };. It also offers code completion for these values, targets, etc. Maybe it does more, but that's enough for me to use it. I hate when my code is full of false-positive warnings.



That alone is plenty - I love that - thanks again for sharing!

akincer Avatar
akincer Avatar akincer | posted 2 years ago

Just when I was getting into Vue NOW you tell me that I probably won't need it using this methodology LOL

Just listening to the video this sounds like what I would prefer since I had the distinct feeling going Vue heavy was leaving behind much of what I had already learned with the Symfony world.

1 Reply

Hey @Aaron!

Yea... sorry about that! They really are both *wonderful* technologies. But you're 100% correct: Stimulus allow you to take what you already know - the "build your HTML inside Symfony" paradigm - and then add professional, fun-to-write, highly functional JavaScript on top of that, instead of doing something "totally" different. That being said, you absolutely CAN still use Vue to write "widgets" that might be *highly* responsive... where it just feels easier to do that in Vue. You can render Vue components from Stimulus super easily (and we talk about how later in the tutorial).


akincer Avatar

Oh my. I'm only on the 8th video and I'm already loving this. My goodness this is exactly how simplified I've been wishing front-end js dev worked.

1 Reply
Joel R. Avatar
Joel R. Avatar Joel R. | posted 1 year ago

Is there a tutorial before this one I should have done to get setup? I downloaded the code package and it doesn't appear to be all of the files necessary to start with. What are the steps to add the missing components? I'm using Symfony 6.


Hey Joel R.

Could you tell me what components are missing? Also, could you double-check that you didn't miss any setup step specified in the README file?


Peter A. Avatar
Peter A. Avatar Peter A. | posted 1 year ago

Hi Ryan

I did the docker-compose up -d and started the symfony webserver symfony serve -d. When I go to localhost:8000 i am getting

SQLSTATE[HY000] [1049] Unknown database 'root'

Peter A. Avatar

My bad.. Misread the instructions.


Woo! I'm glad you got it sorted :).


Tomasz N. Avatar
Tomasz N. Avatar Tomasz N. | posted 2 years ago

Hi Ryan, divine course as always :) but I missed one thing. How i should use translation in super proper way. In PHPStorm when i use twig and trans i can add phrase to translation file. There is a similar way in stimulus controller?


Hey Hesus,

Good question! Unfortunately, no... you need to translate everything you need in Twig template and pass the translated strings to the Stimulus controller somehow. The easiest way probably is to put translated strings on data attributes so you could read them later from the Stimulus controller. Or, if you have a lot of translations, you may want to open a script tag in the template and put an object of translated strings on "window" global variable that you will be able to read later from your Stimulus controller.


1 Reply
Georg H. Avatar
Georg H. Avatar Georg H. | posted 2 years ago

Hi there, thanks a lot for this tutorial and the Stimulus bridge! I really like this approach. On the github page it is noted, that "Symfony UX Stimulus bridge is currently considered experimental". I'm working on a project that ends by the end of 2022. Do you think by then will be a version of Stimulus bridge around that can be considered stable? Thanks again.



Hey Georg,

Thank you for your kind words about this tutorial, you made our day! :) Yes, it's still "experimental" thing, but it mostly mean that some BC breaks might be introduced during the way, and upgrade to the minor version of it may require some extra work, i.e. it may need a bit more work than you do usually when upgrade other Symfony components to their minor versions. So, you can totally use this in your project, but keep in mind some possible BC breaks on upgrades. Bbut if you test your project well with functional testing - tests mostly should cover your back on ugprades and point to problematic spots.

Fairly speaking, it's difficult to say how long it might be considered as "experimental", but it's been actively developed, and has a huge interest in the Symfony community lately, so I think it might become as not experimental at the end of 2022, but that's just mywild prediction, I can't be sure 100%... it just has good chances for this looking at it currently :)

I hope this helps!


Georg H. Avatar

Hey Victor,
yes, your comments are helpful and give me a broader picture. I am excited to see what we will achieve with Symfony UX in our project. Thanks, greetings!


Hey Georg,

I'm happy to hear this! Good luck with your project and Symfony UX integration ;)


shirleenkneppers Avatar
shirleenkneppers Avatar shirleenkneppers | posted 2 years ago

Hi @Ryan, just a quick headsup to maybe give some info for those who is using the new Mac Book with the M1 chips. I am currently not able to install mysql 5.7 it gives me this error "ERROR: no matching manifest for linux/arm64/v8 in the manifest list entries" I am currently looking for a solution but will let you know when I have one. I haven't had an issue like this on the Vue tutorial so interesting that it is having an issue here.

shirleenkneppers Avatar
shirleenkneppers Avatar shirleenkneppers | shirleenkneppers | posted 2 years ago | edited

Ok it's working now. I just changed the docker-compose.yaml file

version: '3.7'
          platform: linux/x86_64
          image: 'mariadb:10.5.10'
               MYSQL_ROOT_PASSWORD: password
                - '3306'

Have you found a solution for this for mysql. I'm still getting that error


Hey Robert,

What error exactly do you have? Did you change the image to MySQL? Could you share your docker-compose.yaml?



Yo shirleenkneppers!

Thanks for posting about this! So it works if you changed over to the mariadb image with the x86_64 platform. I don't have an M1 chip, so I don't know too much about this yet. What's odd is that, like you said, you didn't have an issue on the vue tutorial... which I think has the same config.

Anyways, if this is a legit issue, I'm sure we'll start to see other people with it :). And if so, we'll see what change we can make to the Docker file so it works for everyone.


shirleenkneppers Avatar
shirleenkneppers Avatar shirleenkneppers | weaverryan | posted 2 years ago

If they are the same setup maybe it's due to it having the same name? I didn't try changing it to mysql though. But I know that due to 5.6 Mac might not want to use it anymore as it is reaching end of life. So could be a number of issues. The old file didn't have platform: in it when I tried setting up the database for your information. I added that extra. It could be people just need to add that to make it work. I just decided to change to Mariadb due to I like it more than mysql. :) hope this help someone :)

1 Reply
Dewald Avatar

Does Symfony UX work equally well with Symfony 4.4, or are there any gotchas?


Hey Jeremy,

Yeah, it should work equally well with both Symfony 4.4 / Symfony 5.x versions. At least, nothing I know about that might cause problems.



Even though we can use jQuery with it. What do you recommend? Should we use jQuery with it or not? Technically speaking. Every single jQuery snippet can be converted to a stimulus controller, so that won't be a problem (unless we have a site with jQuery all over the place). Is there any particular best practices when coding using stimulus?


Hey Piter,

In most cases you probably don't need jQuery. If you can avoid using it - great, definitely go with VanillaJS or use native Stimulus features, because jQuery is kinda heavy, and not include it on the page will give you some performance benefits. In other words, it's kind of overkill to use jQuery just to find element by CSS id or class. But if you get used to it - you can still continue using it, there's nothing critical, and it works great. So it's completely up to you whether use it or no.



That's what I thought. I am refactoring my app to fully use stimulus. Waiting for a production release of bootstrap 5 since jQuery is not longer a dependency in that version. Other than that, I think it is time to move away from jQuery all-together.


Hey Piter,

Yes, as you said, libraries are trying to make themselves jQuery-independent so that give you a choice to use it or no - most JS geeks do not like jQuery and I suppose that's why it's going this way. There's nothing wrong with jQuery actually, and it still may be useful in some cases as it has a lot of features out of the box, but using it for simple finding of elements on the page is probably an overkill :) Moreover, with the stimulus finding elements makes even easier thanks to targets ;)

So, if you think you don't need jQuery - great, get rid of it, you will definitely have some benefits. But if you still need it - that's OK too, you can continue using it because its a great tool as well ;)


Krzysztof K. Avatar
Krzysztof K. Avatar Krzysztof K. | posted 2 years ago

Gents, why Stimulus? Why not Inertia.js?


Hey Krzysztof K.!

Excellent question! Victor is right - it's mostly just 2 different philosophies. If I understand it correctly, Inertia.js is based around the idea of rendering HTML in JavaScript, and they make that a lot easier. Stimulus is about rendering HTML on the server and then enhancing it with JavaScript. This lets me code where my strength is (Twig, PHP, etc) but get all the benefits of a SPA. One cool thing about Stimulus is also how *easy* it is to render a React app with props that are passed to you from the server (the core of what Inertia.js does). We even have plans to create a special React and Vue controller so that you could basically say (in Twig) "Render the ABC React component and pass it these props", where those props could be anything, even an object that's serialized to JSON. So again, this is very similar to Inertia.js... but it's only one thing that Stimulus (and Turbo) can do :).



Hey Krzysztof,

Good question, and I personally don't know the exact answer behind of it as I know nothing about Inertia.js unfortunately. I found some related thread about it here: https://github.com/symfony/... - you might be interesting to read it. But basically, that's how guys behind the Symfony UX decided to go.


Cat in space

"Houston: no signs of life"
Start the conversation!

This tutorial works perfectly with Stimulus 3!

What PHP libraries does this tutorial use?

// composer.json
    "require": {
        "php": ">=8.1",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "composer/package-versions-deprecated": "", //
        "doctrine/annotations": "^1.0", // 1.11.1
        "doctrine/doctrine-bundle": "^2.2", // 2.2.3
        "doctrine/doctrine-migrations-bundle": "^3.0", // 3.0.2
        "doctrine/orm": "^2.8", // 2.8.1
        "phpdocumentor/reflection-docblock": "^5.2", // 5.2.2
        "sensio/framework-extra-bundle": "^5.6", // v5.6.1
        "symfony/asset": "5.2.*", // v5.2.3
        "symfony/console": "5.2.*", // v5.2.3
        "symfony/dotenv": "5.2.*", // v5.2.3
        "symfony/flex": "^1.3.1", // v1.18.5
        "symfony/form": "5.2.*", // v5.2.3
        "symfony/framework-bundle": "5.2.*", // v5.2.3
        "symfony/property-access": "5.2.*", // v5.2.3
        "symfony/property-info": "5.2.*", // v5.2.3
        "symfony/proxy-manager-bridge": "5.2.*", // v5.2.3
        "symfony/security-bundle": "5.2.*", // v5.2.3
        "symfony/serializer": "5.2.*", // v5.2.3
        "symfony/twig-bundle": "5.2.*", // v5.2.3
        "symfony/ux-chartjs": "^1.1", // v1.2.0
        "symfony/validator": "5.2.*", // v5.2.3
        "symfony/webpack-encore-bundle": "^1.9", // v1.11.1
        "symfony/yaml": "5.2.*", // v5.2.3
        "twig/extra-bundle": "^2.12|^3.0", // v3.2.1
        "twig/intl-extra": "^3.2", // v3.2.1
        "twig/twig": "^2.12|^3.0" // v3.2.1
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.0
        "symfony/debug-bundle": "^5.2", // v5.2.3
        "symfony/maker-bundle": "^1.27", // v1.30.0
        "symfony/monolog-bundle": "^3.0", // v3.6.0
        "symfony/stopwatch": "^5.2", // v5.2.3
        "symfony/var-dumper": "^5.2", // v5.2.3
        "symfony/web-profiler-bundle": "^5.2" // v5.2.3

What JavaScript libraries does this tutorial use?

// package.json
    "devDependencies": {
        "@babel/preset-react": "^7.0.0", // 7.12.13
        "@popperjs/core": "^2.9.1", // 2.9.1
        "@symfony/stimulus-bridge": "^2.0.0", // 2.1.0
        "@symfony/ux-chartjs": "file:vendor/symfony/ux-chartjs/Resources/assets", // 1.1.0
        "@symfony/webpack-encore": "^1.0.0", // 1.0.4
        "bootstrap": "^5.0.0-beta2", // 5.0.0-beta2
        "core-js": "^3.0.0", // 3.8.3
        "jquery": "^3.6.0", // 3.6.0
        "react": "^17.0.1", // 17.0.1
        "react-dom": "^17.0.1", // 17.0.1
        "regenerator-runtime": "^0.13.2", // 0.13.7
        "stimulus": "^2.0.0", // 2.0.0
        "stimulus-autocomplete": "^2.0.1-phylor-6095f2a9", // 2.0.1-phylor-6095f2a9
        "stimulus-use": "^0.24.0-1", // 0.24.0-1
        "sweetalert2": "^10.13.0", // 10.14.0
        "webpack-bundle-analyzer": "^4.4.0", // 4.4.0
        "webpack-notifier": "^1.6.0" // 1.13.0