Vue 3 pattern for multiple layouts in component

I am working on a Vue3 component. According to the design, there are two slightly different variations of the layout, a simplified example:

  1. Two inner components in the top row, slot below them
<div class="flex flex-col">
   <div class="flex">
      <InnerComponent1/>
      <InnerComponent2/>
   </div>
   <slot/>
</div>
  1. Two inner components in the left column, slot on the right
<div class="flex flex-col">
   <div class="flex">
      <InnerComponent1/>
      <slot/>
   </div>
   <InnerComponent2/>
</div>

What is the right way to implement this in Vue 3? One obvious way is to pass a layout property, then just duplicate the whole div with v-if="layout === 'type1'" etc., but this doesn’t look good, there will be a lot of code duplication.

You could create each layout as its own component replacing all content with slots. Then use a dynamic component to choose which layout to use at runtime. Insert the desired content into each slot, and then let the dynamic component handle the layout of those slots.

LayoutA.vue

<template>
  <div class="flex flex-col">
    <div class="flex">
      <slot name="inner1" />
      <slot name="inner2" />
    </div>
    <slot />
  </div>
</template>

LayoutB.vue

<template>
  <div class="flex flex-col">
    <div class="flex">
      <slot name="inner1" />
      <slot />
    </div>
    <slot name="inner2" />
  </div>
</template>

Component.vue

<template>
  <component :is="layout">
    <template #inner1>
      <InnerComponent1 />
    </template>
    <template #inner2>
      <InnerComponent2 />
    </template>
    <template #default>
      <slot />
    </template>
  </component>
</template>

<script setup>
  import LayoutA from './LayoutA.vue';
  import LayoutB from './LayoutB.vue';

  const layout = ... // insert logic here that decides LayoutA or LayoutB
</script>

Vue Playground example

Leave a Comment