How to properly add and remove class to element in custom directive?

Hello,

I have a problem with classes when component with :class binding and custom directive is combined.

My component - simple button that just manages focus class.

Vue.component("my-button", {
  data() {
    return {
      hasFocus: false,
    };
  },
  methods: {
    onFocus() {
      this.hasFocus = true;
    },
    onBlur() {
      this.hasFocus = false;
    }
  },
  template: `<button class="my-button" :class="{ 'has-focus': hasFocus }" @focus="onFocus" @blur="onBlur"><slot></slot></button>`
});

My directive - just adds class.

Vue.directive("my-directive", {
  bind(el) {
    el.classList.add("my-directive");
  },
  unbind(el) {
    el.classList.remove("my-directive");
  },
});

The problem is when the hasFocus value changes, the component :class is recalculated, however it also removes the .my-directive class added by the directive, making the directive useless.

Here’s jsfiddle for more complete example: https://jsfiddle.net/d05ywxjm/1/

So my question is, how to properly manage class on element via directive?
Or is this a bug of :class binding?

1 Like

Did you manage to solve this problem?

I am facing this issue as well. Would be nice to be able to specify persistent classes.

Just changing bind to update should solve the problem

I’m also facing this problem. Using bind together with update or componentUpdated solves the issue for 90% of cases, but it’s still unreliable and classes sometimes get wiped.

Is there really no way to add to the static classlist of a component / vnode? It seems modifying el.classList from inside a directive is no-go, leaving no possible ways to interact with a classList from inside a directive

I was adding a class to my element in the bind, and it’d get lost along the way in some scenarios. I found that wrapping my code in nextTick in componentUpdated allowed me to successfully add it back to the element. Without nextTick, it was only working some of the time.

Vue.nextTick(() => {
el.classList.add(‘your-class’);
});