javascriptvue.jsvuejs2

Use style tags inside vuejs template and update from data model


I would like to dynamically update styles inside style tags.

However creating a container model for Vue, removes the style tags. I know style tags should belong in the head of the page, but this is just for the sake of ease of use.

So what I would like to have is a wrapper with an element and style tags inside:

<div class="setting">
  <style>
    .setting input {
      background: {{bgColor}};
    }
  </style>
  <input class="setting" type="text" v-model="bgColor">
</div>

The value from the input should update the value of the css style. Whenever done with simple div elements this works, but style tags seem to be a problem

The javascript set up is the following:

new Vue({
    el: '.setting',
    data: {
      bgColor: 'red'
    }
});

However when the style tags have a specific id, this could work, but I can't bind it to an input field.

<style id="setting">
  #blue {
    background: {{bg}}
  }
  #blue:hover {
    background: {{bgHover}}
  }
</style>

<div id="blue"></div>

and the js:

new Vue({
    el: '#setting',
    data: {
      bg: 'blue',
      bgHover: 'red'
    }
});

Can someone help me understand how I can achieve updating values between style tags. jsfiddle set up

Thanks.


Solution

  • Vue 3:

    For Vue3 users: https://v3-migration.vuejs.org/breaking-changes/render-function-api.html#render-function-argument


    Vue 2:

    Here's what I think is a good workaround/solution.

    It is just a custom component, so it's as reusable as it gets. All of Vue's goods like v-if can all be used.

    Another pro is that the styles generated will be there only as long as the component is!

    Vue.component('v-style', {
      render: function (createElement) {
        return createElement('style', this.$slots.default)
      }
    });
    
    
    // demo usage, check the template
    new Vue({
      el: '#app',
      data: {
        bgColor: 'red'
      }
    })
    <script src="https://unpkg.com/vue"></script>
    
    <div id="app" class="stuff">
      <v-style>
        .stuff input {
          background: {{bgColor}};
        }
      </v-style>
    
      Remove "red" and type "yellow":
      <input class="setting" type="text" v-model="bgColor">
    </div>

    The one drawback I see is that since the name of the tag is <v-style> (or whatever you chose to call it) and not <style>, the IDEs may not color it nicely. But otherwise it'll just be like a regular <style> tag.


    Standard solution: using v-bind:style

    This doesn't modify style tags, but the standard way of setting styles is using object style bindings.

    Basically you'd use a :style attribute and assign to it the CSS properties of the style in the form of an object. Demo below.

    new Vue({
      el: '.setting',
      data: {
        bgColor: 'red'
      },
      computed: {
        inputStyles() {
          return {
            background: this.bgColor
          }
        }
      }
    });
    <script src="https://unpkg.com/vue"></script>
    
    <div class="setting">
      Remove "red" and type "yellow":
      <input class="setting" type="text" v-model="bgColor" :style="inputStyles">
    </div>