Harshal Patil
Harshal Patil

Reputation: 20960

How to apply classes to Vue.js Functional Component from parent component?

Suppose I have a functional component:

<template functional>
    <div>Some functional component</div>
</template>

Now I render this component in some parent with classes:

<parent>
    <some-child class="new-class"></some-child>
</parent>

Resultant DOM doesn't have new-class applied to the Functional child component. Now as I understand, Vue-loader compiles Functional component against render function context as explained here. That means classes won't be directly applied and merge intelligently.

Question is - how can I make Functional component play nicely with the externally applied class when using a template?

Note: I know it is easily possible to do so via render function:

Vue.component("functional-comp", {
    functional: true,
    render(h, context) {
        return h("div", context.data, "Some functional component");
    }
});

Upvotes: 27

Views: 12138

Answers (3)

miorey
miorey

Reputation: 946

You have to use props to pass attributes to components https://v2.vuejs.org/v2/guide/components.html#Passing-Data-to-Child-Components-with-Props

Upvotes: -1

Alexander Kim
Alexander Kim

Reputation: 18382

Render function inside a functional component example, to supplement @Daniel's answer:

render(createElement, { data } {
  return createElement(
    'div',
    {
      class: {
        ...(data.staticClass && {
          [data.staticClass]: true,
        })
      },
      attrs: {
        ...data.attrs,
      }
    }
  )
}

We can use ES6 computed property name in order to set a static class.

Upvotes: 1

Daniel
Daniel

Reputation: 35684

TL;DR;

Use data.staticClass to get the class, and bind the other attributes using data.attrs

<template functional>
  <div class="my-class" :class="data.staticClass || ''" v-bind="data.attrs">
    //...
  </div>
</template>

Explanation:

v-bind binds all the other stuff, and you may not need it, but it will bind attributes like id or style. The problem is that you can't use it for class because that's a reserved js object so vue uses staticClass, so binding has to be done manually using :class="data.staticClass".

This will fail if the staticClass property is not defined, by the parent, so you should use :class="data.staticClass || ''"

Example:

I can't show this as a fiddle, since only "Functional components defined as a Single-File Component in a *.vue file also receives proper template compilation"

I've got a working codesandbox though: https://codesandbox.io/s/z64lm33vol

Upvotes: 42

Related Questions