blog   |   14 Jun, 2022

Vue: Dynamic components

Flexibility at its finest!

Adapting components dynamically in Vue involves seamlessly switching between components by leveraging the 'is' attribute with the reserved <component> element.

Let’s explore an example to grasp the concept of dynamic components better. Imagine having distinct components named Overview, News Feed, and Activity History, each displaying text indicating its identity.

<!-- Overview -->

<template><div class="tab">Overview</div></template>

<!-- News Feed -->

<template><div class="tab">News Feed</div></template>

<!-- Activity History -->

<template><div class="tab">Activity History</div></template>

Our objective is to create an interface with a set of clickable tabs. Clicking on any tab should dynamically render a specific component. Dynamic Tab Interface

When navigating between tabs, we aim to have components dynamically unmounted and mounted without resorting to routing. While this could be accomplished by conditionally displaying child templates using directives like v-if and v-else, Vue's dynamic components perfectly serve this purpose.

Within our app's parent component, let's first import the three individual components to access them in the template. Additionally, we’ll create a reactive property named 'currentTab' with an initial value of "Overview". We’ll generate three separate tab buttons, each corresponding to a component we intend to display. Utilizing the v-for directive, we’ll iterate through the 'tabs' list and render a collection of <button> elements. Each button will have the tab value bound to its key attribute. Additionally, an '.active' class will be dynamically applied if the tab is selected, and a click handler will update the 'currentTab' value accordingly.

<template>
  <div class="demo">
    <button
      v-for="(_, tab) in tabs"
      :key="tab"
      :class="['tab-button', { active: currentTab === tab }]"
      @click="currentTab = tab"
    >
      {{ tab }}
    </button>
  </div>
</template>

<script setup>
  import { ref } from "vue";
  import Overview from "./components/Overview.vue";
  import NewsFeed from "./components/NewsFeed.vue";
  import ActivityHistory from "./components/ActivityHistory.vue";

  const currentTab = ref("Overview");
  const tabs = {
    Overview,
    NewsFeed,
    ActivityHistory,
  };
</script>

 

Dynamic components

To dynamically render a specific child component, we’ll bind an 'is' attribute to the reserved <component> element. The value associated with the 'is' attribute should correspond to the child component we wish to render dynamically. In our case, we’ll utilize the 'currentTab' data property to determine the selected child component.

<template>
  <div class="demo">
    <button
      v-for="(_, tab) in tabs"
      :key="tab"
      :class="['tab-button', { active: currentTab === tab }]"
      @click="currentTab = tab"
    >
      {{ tab }}
    </button>
    <component :is="tabs[currentTab]" class="tab"></component>
  </div>
</template>

<script setup>
  import { ref } from "vue";
  import Overview from "./components/Overview.vue";
  import NewsFeed from "./components/NewsFeed.vue";
  import ActivityHistory from "./components/ActivityHistory.vue";

  const currentTab = ref("Overview");
  const tabs = {
    Overview,
    NewsFeed,
    ActivityHistory,
  };
</script>

 

Preserving state is crucial when dealing with dynamic components. By default, when a component is unmounted, its state is lost. However, Vue offers a way to retain the state of dynamic components using the <KeepAlive> component.

<template>
  <div class="demo">
    <KeepAlive>
      <component :is="tabs[currentTab]" class="tab"></component>
    </KeepAlive>
  </div>
</template>

<script setup>
  // ...
</script>

Upon implementing these adjustments, we’ll notice that the state for each respective child component remains preserved even as we dynamically switch between components.

I hope you enjoyed reading this!