Skip to content

How to use Vue in Twig?

Kevin Driessen edited this page Apr 6, 2021 · 5 revisions

To start using Vue in Twig should be easy enough by following Symfony's guide "Enabling Vue.js", but after this you're pretty much on your own. There's ton of information about Vue and there's ton of information about Symfony, but guides for combining them are few, repeating eachother and often use cumbersome approaches.

Here's a (somewhat opiniated) overview of different approaches:

Approach Pros Cons
1) Using data- attribues - It is easy to understand
- It is easy to setup
- Extra code in html and vue
- Limited ways of usage
2) Creating a Single Page App and use API's - No need for messing around in Twig
- Potentially faster applications
- You're missing out on the benefits Twig has to offer
- Need for API's for just about everything
3) Creating your Vue instance in Twig - More control/flexibility
- Easier to see how data is passed from Twig to Vue
- Lots of javascript-code in Twig
- Difficult to re-use code
4) Creating your vue object in Twig - Maximum control/flexibility
- Easier to see how data is passed from Twig to Vue
- More difficult to understand
- Potentially harder to debug

Like always the best approach depends on your needs and one appraoch doesn't necessarily exclude the other.

1) The data- approach

The first approach is probably the most suggested approach that you'll find in most guides. Using it is simple. In your html (in twig) you can use something like:

<div id="product-info" data-product-name="{{ product.name }}" data-product-price="{{ product.price }}"></div>

Then inside a vue-component you can retrieve this information by using document.getElementById('product-info').dataset.

It is fine for a small example, but it feels like sticking with an approach that was once introduced by jQuery.

When passing down json, you might run into trouble: data-info="{"price": 50}" won't work and data-info='{"message": "granny's spoiling"}' won't work either. And what about computed properties? You can create these in a vue-component, but you won't be able to directly use them inside Twig.

2) The single-page-app approach

This approach actually doesn't fit in the question 'how to use Vue in Twig', since you won't need Twig with this approach. However, it is important to at least consider this approach, since it might be the best approach for lots of applications.

If you want a single page app and/or needed to create API's anyway, then it is obvious that should should pick this approach. Actually, in that case you might want to consider creating a separate front-end application.

When creating a single page app, you create a strong separation between backend and frontend, which can have great benefits. The tradeoff is that you no longer can use Twig's features like {{ path('name_of_your_route') }}, {{ is_granted('voter_attribute') }} and {{ form(form) }}. There's great functionally in Vue that can provide similar solutions, but nonetheless you're missing out on functionality Symfony/Twig has to offer.

There's a big chance you need to implement certain things both serverside and clientside, which can be worthwhile, but certainly requires extra effort.

3) Creating a Vue instance in twig

Creating a Vue instance in Twig makes sense when:

  • You want to keep utilizing functionality that Twig has to offer
  • Using data- attributes aren't sufficient for what you need.
  • You don't want to be forced to create a vue-component out of everything, for example if you only need a computed property.

At moment of writing there are few guides explaining this, so here's a small example:

{% block body %}
    <div id="vue-app">
        <p v-if="seconds > 5">
            @{ seconds } seconds have past.
        </p>
    </div>
{% endblock}

{% block javascripts %}
    {{ parent() }}
    <script>
        new Vue({
            el: '#vue-app',
            delimiters: ['@{', '}'],
            data: () => ({
                seconds: 0,
            }),
            created() {
                setInterval(() => { this.seconds++; }, 1000);
            },
        });
    </script>
{% endblock %}

If you're only using Vue on a limited amount of pages this approach might be best for you. Once you need to this for every page, you'll want a more generic approach. This is where using a vue-object comes in.

4) Creating a vue object in twig

You could think of this approach of being an extension of the third approach. It is practically the same, but creating the Vue-instance is postponed.

Instead of creating the instance in Twig you can create an object only. Afterwards, inside your javascript file (assets/app.js for example), you use this object to create the Vue instance. The same javascript-block in Twig would look like below:

{% block javascripts %}
    <script>
        vue = {
            el: '#vue-app',
            delimiters: ['@{', '}'],
            data: () => ({
                seconds: 0,
            }),
            created() {
                setInterval(() => { this.seconds++; }, 1000);
            },
        };
    </script>
    {{ parent() }}
{% endblock %}

Note that the {{ parent() }} is called after creating the vue-object, so this way the object should be available when your app.js is loaded.

Once you start using an object, you can make alterations to it before you create an instance out of it. If you always use the same #vue-app and delimiters, then you can put that inside your app.js

new Vue(Object.merge({
    el: '#vue-app',
    delimiters: ['@{', '}'],
}, vue))

The SymfonyVuetified embraces this fourth approach to maximize the things you can do.