27

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");
    }
});

3 Answers 3

42

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

Sign up to request clarification or add additional context in comments.

2 Comments

To apply both static and dynamic classes from a parent, e.g. <some-child class="a" :class="{b: true}"/> use :class="[data.staticClass, data.class]" in the child.
How to bind all regular static attributes on childComponent: (1) use :class="data.staticClass" for classes (2) use :style="data.staticStyle" for styles (3) use v-bind="data.attrs" for id etc.
1

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.

Comments

-1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.