One VueJS Component with multiple templates One VueJS Component with multiple templates vue.js vue.js

One VueJS Component with multiple templates


I often accomplish this by passing in a prop and using that prop for conditional rendering.

For example:

<template>    <div>        <div v-if="isActive">RADICAL ACTIVE STATE</div>        <div v-if="!isActive">YOLO NOT ACTIVE</div>    </div><template><script>export default {    props: {        isActive: {            type: Boolean,            required: true,        },    },};</script>

That will probably get you there 80% of the time unless that "single root wrapper" thing is causing you a problem.

In that case, you definitely have options. One of which could be to use a slot and control the conditional rendering upstream. That might result in less markup.

Maybe you could instead just create two components that are each simpler than they would be otherwise. Reducing cyclomatic complexity is always good.

You can also throw v-if on the template itself <template v-if="">.

In my experience today, you cannot use two templates in one single file component (like the one in the code I showed above). Vue doesn't seem to parse the templates correctly. Vue was simply not executing my computed prop or method. It was always rendering the second template, so Vue may have internal logic whereby it loads the "last observed template".

A person will probably find it helpful to read http://vuejs.org/guide/components.html#Fragment_Instance because it illustrates the template instance prop.

It's the closest I've seen to the React equivalent to a stateless dumb component such as:

const ShowNumber = ({ num }) => (    <div>{num}</div>)...<ShowNumber num={1337} />

If my answer here is wetting your appetite but you feel like it still isn't quite what you need, Google "Vue render props" and take a look at how you can do crazy-complex logic inside the render instance prop. It's very similar to React's JSX, but I will say that if you are in this territory, there is probably a simpler way to do it.

I might recommend just creating two single-file components with one template in each, or find a way to use slots and control the behaviour from upstream.

You are also pretty safe to do it like I showed in my example above, because the data flow through the component is unidirectional and deterministic, and the UI will always be a reflection of the props and data. If the props or data change, your component will render the correct elements.

You could do this in the upstream parent component:

<large-widget v-if="someState === 'one'"></large-widget><small-widget v-else-if="someState === 'two'"></small-widget><div v-else>WIDGET IS BORKEN</div>