Cookies Psst! Do you accept cookies?

We use cookies to enhance and personalise your experience.
Please accept our cookies. Checkout our Cookie Policy for more information.

Creating a conditional wrap component in Vue 3

Often it's needed to wrap some part of a template in a wrapper <div> for example. It seems easy using v-if but we have a duplication we'd like to avoid:

<div v-if="isWrapped" class="wrapper">
  <!-- some big chunk of markup -->
</div>
<template v-else>
  <!-- the same big chunk -->
</template>

Let's explore our options how we can solve this task without duplication. Let's call our component <wrap> and our component that wraps the content a wrapper. Sure it should be functional since there's no state to keep.

Our first option would be simple. We support a wrapper component and its props:

See on Vue SFC Playground

import { h } from 'vue';
export default function Wrap({wrapper, ...props}, {slots}){
  return wrapper ? h(wrapper, props, slots.default()) : slots.default();
}

Usage:

<script setup>

import { ref } from 'vue';
import Wrap from './Wrap';

const isWrapped = ref(false);

</script>

<template>
  <wrap :wrapper="isWrapped && 'div'" :="{class: 'wrapper'}">
    <p>
      I'm wrapped
    </p>
  </wrap>
  <button @click="isWrapped = !isWrapped">Toggle wrapper</button>
</template>

The result is pretty sufficient, you can use any wrapper component with a default slot. But a problem here is that for more complex cases like having multiple nested wrappers we should define the wrapper outside our markup since having a functional wrapper component inside :wrapper property looks pretty messy. In the next posts of this series we'll explore other options of defining our conditional wrap component.

Last Stories

What's your thoughts?

Please Register or Login to your account to be able to submit your comment.