Dynamic component rendering in Vue.js lets you display different components based on conditions at runtime. This feature is handy for building flexible, user-friendly, and scalable applications. Instead of hardcoding components into the layout, you can dynamically switch, or load components as needed.
What Is Dynamic Component Rendering?
Normally, components are fixed in the app’s layout. Dynamic component rendering changes this by allowing components to load based on certain conditions. Vue’s <component> tag makes this easy by binding the is attribute to a component name or configuration.
For example:
//Path: src/components/DynamicComponents/Simple.vue <template> <component :is="currentComponent"></component> </template>
Here, currentComponent decides which component is displayed. This approach is useful for switching tabs, showing conditional content, or reusing layouts.
When to Use Dynamic Component Rendering?
Dynamic component rendering is suited for scenarios where flexibility and reusability are priorities. Here are some common use cases:
- Conditional Displays: Replace multiple v-if conditions with dynamic components for a cleaner and simpler structure.
- Tabbed Interfaces: Use dynamic components to show only the active tab’s content in tabbed layouts.
- Reusable Sections: Load different headers, footers, or sidebars without duplicating code.
- Multi-Step Forms: Dynamically load components for each step in a workflow, improving performance and maintainability.
- Dashboards: Create customizable dashboards where widgets or modules are rendered dynamically based on user preferences.
How to Use Dynamic Component Rendering?
Dynamic component rendering in Vue.js revolves around the <component> element. This element dynamically switches the rendered component based on the value of the is attribute.
1) Switching Between Components
Let’s start with a basic example where a button click switches the rendered component.
Step 1: Define the Components
ComponentA.vue
//Path: src/components/DynamicComponents/ComponentA.vue <template> <div> <h2>Component A</h2> <p>This is Component A. Welcome!</p> </div> </template> <script> export default { name: 'ComponentA', }; </script>
ComponentB.vue
//Path: src/components/DynamicComponents/ComponentB.vue <template> <div> <h2>Component B</h2> <p>This is Component B. Welcome!</p> </div> </template> <script> export default { name: 'ComponentB', }; </script>
Step 2: Main Application
Main.vue
//Path: src/components/DynamicComponents/Main.vue <template> <div id="app"> <h1>Dynamic Component Switching Example</h1> <div class="buttons"> <!-- Buttons to Switch Components --> <button @click="currentComponent = 'ComponentA'">Show Component A</button> <button @click="currentComponent = 'ComponentB'">Show Component B</button> </div> <!-- Dynamic Component Rendering --> <component :is="currentComponent" class="dynamic-component"></component> </div> </template> <script> import ComponentA from './ComponentA.vue'; import ComponentB from './ComponentB.vue'; export default { components: { ComponentA, ComponentB, }, data() { return { currentComponent: 'ComponentA', // Default component to render }; }, }; </script>
Output:
How It Works
- Component Registration: ComponentA and ComponentB are imported into App.vue and registered in the components object.
- Dynamic Switching: The currentComponent data property controls which component is displayed.
- Clicking “Show Component A” sets currentComponent to ‘ComponentA’.
- Clicking “Show Component B” sets currentComponent to ‘ComponentB’.
- Dynamic Rendering: The <component> element dynamically renders the component specified by currentComponent.
2) Dynamic Tabs with Props
Dynamic components in Vue.js let you easily display different components based on user actions or changes in the app’s state. For example, in a tabbed interface, they allow you to switch between content views while keeping the code clean and organized. You can also make these components interactive by passing data to them using props. Imagine a dashboard with widgets like User Info, Notifications, and Tasks, where each widget is a separate component.
Step 1: Define the Components
Tab1.vue
//Path: src/components/DynamicComponents/Tab1.vue <template> <div> <h3>Welcome to Tab 1</h3> <p>This is the content for Tab 1.</p> </div> </template> <script> export default{ name: 'Tab1', props: ['message'] } </script>
Tab2.vue
//Path: src/components/DynamicComponents/Tab2.vue <template> <div> <h3>Welcome to Tab 2</h3> <p>This is the content for Tab 2.</p> </div> </template> <script> export default{ name: 'Tab2', props: ['message'] } </script>
Tab3.vue
//Path: src/components/DynamicComponents/Tab3.vue <template> <div> <h3>Welcome to Tab 3</h3> <p>This is the content for Tab 3.</p> </div> </template> <script> export default{ name: 'Tab3', props: ['message'] } </script>
Step 2: Main Application
App.vue
<template> <div id="app"> <h1>Dynamic Tabs with Props Example</h1> <!-- Tab Navigation --> <div class="tab-buttons"> <button v-for="tab in tabs" :key="tab.name" @click="currentTab = tab.component"> {{ tab.name }} </button> </div> <!-- Dynamic Component Rendering --> <component :is="currentTab" v-bind="currentTabProps" class="dynamic-tab"></component> </div> </template> <script> import Tab1 from './Tab1.vue'; import Tab2 from './Tab2.vue'; import Tab3 from './Tab3.vue'; export default { components: { Tab1, Tab2, Tab3, }, data() { return { // Tabs configuration tabs: [ { name: 'Tab 1', component: 'Tab1', props: { message: 'Hello from Tab 1!' } }, { name: 'Tab 2', component: 'Tab2', props: { info: 'Data for Tab 2' } }, { name: 'Tab 3', component: 'Tab3', props: { details: 'Details for Tab 3' } }, ], currentTab: 'Tab1', // Default tab component }; }, computed: { // Find and provide the props for the current tab currentTabProps() { const tab = this.tabs.find(t => t.component === this.currentTab); return tab ? tab.props : {}; }, }, }; </script>
Output:
How It Works
- Tabs Configuration: In App.vue, there is a tabs array that defines each tab’s name, associated component, and the props it will use.
- Dynamic Rendering: The <component> element is used to dynamically render the component for the currently selected tab (currentTab). Props are passed to the dynamic component using the v-bind directive.
- Switching Tabs: When a tab button is clicked, the currentTab value is updated. This triggers Vue to re-render the dynamic component for the selected tab.
3) Rendering Lists of Dynamic Components in Vue.js
In Vue.js, rendering a list of dynamic components is a useful feature, especially for things like dashboards or showing different types of widgets based on data. For example, you can create a dynamic dashboard with widgets like User Info, Notifications, and Tasks. Each widget is its own component, and they can be displayed dynamically based on the data provided.
Child Components
UserInfo.vue
<template> <div class="widget"> <h3>User Info</h3> <p><strong>Name:</strong> {{ name }}</p> <p><strong>Email:</strong> {{ email }}</p> </div> </template> <script> export default { props: { name: String, email: String, }, }; </script>
Notification.vue
<template> <div class="widget"> <h3>Notifications</h3> <ul> <li v-for="(notification, index) in notifications" :key="index"> {{ notification }} </li> </ul> </div> </template> <script> export default { props: { notifications: Array, }, }; </script>
Task.vue
<template> <div class="widget"> <h3>Tasks</h3> <ul> <li v-for="(task, index) in tasks" :key="index"> {{ task }} </li> </ul> </div> </template> <script> export default { props: { tasks: Array, }, }; </script>
Parent Component:
App.vue
<template> <div id="app"> <h1>Dynamic Dashboard</h1> <div class="dashboard"> <!-- Render List of Dynamic Components --> <component v-for="(widget, index) in widgets" :is="widget.type" v-bind="widget.props" :key="index" class="dashboard-widget" ></component> </div> </div> </template> <script> import UserInfo from './UserInfo.vue'; import Notifications from './Notification.vue'; import Tasks from './Tasks.vue'; export default { components: { UserInfo, Notifications, Tasks, }, data() { return { // List of widgets to render dynamically widgets: [ { type: 'UserInfo', props: { name: 'ABC ', email: 'abc.xyz@example.com', }, }, { type: 'Notifications', props: { notifications: [ 'New comment on your post', 'Your profile has been updated', ], }, }, { type: 'Tasks', props: { tasks: ['Complete the Vue.js tutorial', 'Update the project plan', 'Fix the login bug'], }, }, ], }; }, }; </script>
Output:
How It Works
- Dynamic Components: The <component> element dynamically renders a component specified by the type of property in the widgets array.
- Widgets Array: Each object in the widgets array contains:
- type: The name of the component to render (e.g., ‘UserInfo’).
- props: The data to pass to the component as props.
- Reusability
- Each widget is a self-contained component with its own logic and props, making it reusable.
- Data-Driven UI
- Adding, removing, or modifying widgets is as simple as updating the widgets array in the parent component.
4) Lazy Loading Dynamic Components
Lazy loading dynamic components helps improve performance by loading components only when they are needed. In Vue.js, you can use asynchronous functions to lazy-load components, making large apps with many components load faster.
Child Components
Tab1.vue
<template> <div> <h3>Welcome to Tab 1</h3> <p>This is the content for Tab 1.</p> </div> </template> <script> export default{ name: 'Tab1', props: ['message'] } </script>
Tab2.vue
<template> <div> <h3>Welcome to Tab 2</h3> <p>This is the content for Tab 2.</p> </div> </template> <script> export default{ name: 'Tab2', props: ['message'] } </script>
Tab3.vue
<template> <div> <h3>Welcome to Tab 3</h3> <p>This is the content for Tab 3.</p> </div> </template> <script> export default{ name: 'Tab3', props: ['message'] } </script>
Parent Component:
App.vue
<template> <div id="app"> <h1>Lazy Loading Dynamic Components</h1> <!-- Buttons to Load Components --> <div class="tab-buttons"> <button v-for="tab in tabs" :key="tab.name" @click="loadTab(tab.component)"> {{ tab.name }} </button> </div> <!-- Lazy-Loaded Dynamic Component --> <component v-if="currentTab" :is="currentTab" class="dynamic-tab"></component> </div> </template> <script> import { markRaw } from 'vue'; export default { data() { return { // Configuration for dynamic components tabs: [ { name: 'Tab 1', component: () => import('./Tab1.vue') }, { name: 'Tab 2', component: () => import('./Tab2.vue') }, { name: 'Tab 3', component: () => import('./Tab3.vue') }, ], currentTab: null, // Initially no tab is loaded }; }, methods: { async loadTab(componentLoader) { // Resolve the module and mark it as raw const resolvedComponent = await componentLoader(); this.currentTab = markRaw(resolvedComponent.default); }, }, }; </script> <style> #app { font-family: Arial, sans-serif; max-width: 600px; margin: 50px auto; text-align: center; } .tab-buttons { margin-bottom: 20px; } button { padding: 10px 15px; margin: 0 5px; border: none; background-color: #007bff; color: white; font-size: 16px; border-radius: 4px; cursor: pointer; } button:hover { background-color: #0056b3; } .dynamic-tab { margin-top: 20px; padding: 20px; border: 1px solid #ddd; border-radius: 8px; background: #f9f9f9; } </style>
Output:
Conclusion
Dynamic component rendering in Vue.js is a powerful feature for building flexible and modern apps. It lets developers show components based on conditions, switch layouts, and improve workflows, leading to cleaner and more scalable code. Whether you’re making a multi-step form, a tabbed interface, or a customizable dashboard, learning to use dynamic components will enhance your Vue.js skills.