DEV Community

Cover image for Config-driven Vue Interfaces with Dynamic Components
Jakub Andrzejewski
Jakub Andrzejewski

Posted on

Config-driven Vue Interfaces with Dynamic Components

Modern Vue applications are no longer built from hardcoded layouts alone. As products scale, UIs increasingly need to adapt to configuration, CMS content, feature flags, experiments, or backend-driven schemas.

This is where config-driven interfaces and Vue’s dynamic components (<component :is>) truly shine.

Instead of baking layout decisions into templates, you let configuration decide what gets rendered — and Vue handles how it’s rendered.

In this article, we’ll explore:

  • What config-driven UI means in Vue
  • How <component :is> enables truly dynamic rendering
  • Patterns for CMS-driven and backend-driven interfaces
  • Common pitfalls and how to avoid them
  • When dynamic components are powerful — and when they’re not

Enjoy!

🤔 What Are Config-driven Interfaces in Vue?

A config-driven interface is one where structure, composition, or behavior is controlled by data, not hardcoded templates.

Instead of writing:

<Hero />
<Features />
<Testimonials />
Enter fullscreen mode Exit fullscreen mode

You render UI based on configuration:

[
  { type: 'hero', props: { title: 'Hello' } },
  { type: 'features', props: { items: [...] } },
  { type: 'testimonials', props: { quotes: [...] } }
]
Enter fullscreen mode Exit fullscreen mode

This approach is common in:

  • CMS-driven websites
  • Page builders
  • Design systems
  • A/B testing
  • White-label products
  • Dashboard builders

Vue’s <component :is> is the core primitive that makes this possible.

🟢 Dynamic Components with <component :is>

At its core, Vue allows you to dynamically choose which component to render:

<component :is="currentComponent" />
Enter fullscreen mode Exit fullscreen mode

Where currentComponent can be:

  • A component reference
  • A registered component name
  • A function that resolves a component
  • A value from configuration

This makes Vue ideal for config-driven rendering — as long as you structure it correctly.

Mapping Config to Components (Recommended Pattern)

Avoid rendering arbitrary strings directly. Instead, define an explicit mapping:

import HeroBlock from '@/components/HeroBlock.vue'
import FeaturesBlock from '@/components/FeaturesBlock.vue'

const componentMap = {
  hero: HeroBlock,
  features: FeaturesBlock
}
Enter fullscreen mode Exit fullscreen mode

Then render safely:

<component
  :is="componentMap[block.type]"
  v-bind="block.props"
/>
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Strong boundaries
  • Better type safety
  • Easier refactoring
  • Clear ownership of what can be rendered

This pattern scales well with CMS-driven systems.

Rendering Lists of Dynamic Blocks

Most config-driven UIs involve iteration:

<template>
  <component
    v-for="block in blocks"
    :key="block.id"
    :is="componentMap[block.type]"
    v-bind="block.props"
  />
</template>
Enter fullscreen mode Exit fullscreen mode

This allows:

  • Reordering content without code changes
  • Enabling/disabling blocks via config
  • Experimenting with layouts safely

The UI becomes data-driven, not template-driven.

CMS-driven Interfaces in Practice

A typical CMS payload might look like:

{
  "blocks": [
    { "id": 1, "type": "hero", "props": { "title": "Welcome" } },
    { "id": 2, "type": "features", "props": { "items": [] } }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Vue consumes this naturally using dynamic components — no conditionals, no giant v-if chains.

This is significantly more maintainable than:

<Hero v-if="type === 'hero'" />
<Features v-else-if="type === 'features'" />
Enter fullscreen mode Exit fullscreen mode

🟢 Common Pitfalls of Dynamic Components

Overusing Dynamic Rendering

Not every UI should be config-driven.

Avoid dynamic components when:

  • The layout is static
  • The structure rarely changes
  • The complexity outweighs flexibility

Dynamic components introduce indirection — use them intentionally.

Leaking Logic into Configuration

Configuration should describe what, not how.

Bad:

{ "type": "hero", "showIf": "user.isAdmin && env === 'prod'" }
Enter fullscreen mode Exit fullscreen mode

Good:

  • Keep logic in code
  • Keep config declarative
  • Validate inputs before rendering

Performance Considerations

Dynamic components are still Vue components:

  • They mount
  • They update
  • They re-render

Optimize with:

  • markRaw for component maps
  • KeepAlive for frequently toggled blocks
  • defineAsyncComponent for heavy CMS sections

Dynamic doesn’t mean free — measure when needed.

📖 Learn more

If you would like to learn more about Vue, Nuxt, JavaScript or other useful technologies, checkout VueSchool by clicking this link or by clicking the image below:

Vue School Link

It covers most important concepts while building modern Vue or Nuxt applications that can help you in your daily work or side projects 😉

🧪 Advance skills

A certification boosts your skills, builds credibility, and opens doors to new opportunities. Whether you're advancing your career or switching paths, it's a smart step toward success.

Check out Certificates.dev by clicking this link or by clicking the image below:

Certificates.dev Link

Invest in yourself—get certified in Vue.js, JavaScript, Nuxt, Angular, React, and more!

✅ Summary

Config-driven interfaces are one of Vue’s quiet superpowers.

In this article you learned:

  • What config-driven UI means in Vue
  • How <component :is> enables dynamic rendering
  • Patterns for CMS-driven and backend-driven layouts
  • Common pitfalls to avoid
  • When dynamic components are worth the complexity

Used intentionally, dynamic components turn Vue into a flexible UI runtime — not just a templating system.

Take care!
And happy coding as always 🖥️

Top comments (0)