2

Vue.js allows only one root element per component. In most cases, that's fine to wrap a component inside a div tag, but it can sometimes cause unexpected behavior.

For instance, when using Bootstrap, if you put a div between two elements (like <b-row> and <b-col>), the layout gets totally broken.

Many other elements in the framework need to follow a specific order, and that's why having one root element could be problematic.

Is there a way to dynamically set the root element?

To get an idea of what I'm talking about, take a look at this example.

If I have a component my-h1, like this one:

<template>
    <div>
        <h1>Hello world</h1>
    </div>
</template>

which gets called here:

<div id="my-app">
    <my-h1 />
</div>

The code above will produce:

<div id="my-app">
    <div>
        <h1>Hello world</h1>
    </div>
</div>

How can I get this output at one place:

<div id="my-app">
    <p>
        <h1>Hello world</h1>
    </p>
</div>

and at another place, this one:

<div id="my-app">
    <a>
        <h1>Hello world</h1>
    </a>
</div>

(I know these tags don't make any sense, it's only for the purpose of illustration.)

I hope you see what I mean. The component should still have one root element, but it should be set to be different from the default one, with a prop or something else. :)

2
  • I think you can achieve this by using slots, or even by passing a prop and checking in the template... Commented Apr 28, 2019 at 21:50
  • Can you provide me an example pls? Commented Apr 28, 2019 at 21:54

2 Answers 2

4

Just use the special <component> component which allows you to choose the component dynamically:

MyComponent.vue

<template>
  <component :is="is" v-bind="props">
    Hello world
  </component>
<template>
export default {
  props: ['is', 'props'],
}

Usage is like so:

<my-component is="div"/>
<my-component is="p"/>
Sign up to request clarification or add additional context in comments.

Comments

1

With slots you will have to replace the entire component, which I don't think you want.

The other solution will be to pass a type property to your component and do a switch (I don't know if it is compliant with vue general philosophy)

But here is an example about what I was thinking:

<template>
    <template v-if="type === 'div'">
      <div>
        <h1>Hello world</h1>
      </div>
    </template>

    <template v-else-if="type === 'a'">
      <a>
        <h1>Hello world</h1>
      </a>
    </template>

    <template v-else-if="type === 'p'">
      <p>
        <h1>Hello world</h1>
      </p>
    </template>

    <template v-else>
      <i>
        This is a default
        <b>ITALIC TEXT</b>
      </i>
    </template>
</template>

<script>
export default {
  props: {
    type: String
  }
};
</script>

Then you call your component

<component type="div|p|a|whatever"/>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.