Named Views | Vue Router - Multiple Components, One Route ๐ฏ โ
Complex layout management - Render multiple components simultaneously for sophisticated application structures!
๐ฏ Overview โ
Named views allow you to render multiple components at the same route, each in its own named <RouterView> outlet. This powerful feature enables complex layouts like dashboards, admin panels, and applications with multiple content areas that need to update independently.
๐ Key Benefits โ
- Multiple Outlets: Render different components in different viewports
- Independent Updates: Update sections of the page independently
- Complex Layouts: Create sophisticated application structures
- Reusable Components: Share components across different view configurations
๐ก When to Use Named Views โ
๐๏ธ Complex Application Layouts โ
Dashboard Interfaces
- Sidebar navigation with main content area
- Header, footer, and main content sections
- Multiple independent content panels
Admin Panels
- Navigation sidebar with dynamic content
- Multiple data visualization areas
- Independent control panels
๐ง Basic Implementation โ
<template>
<!-- Application layout with named views -->
<div class="app-layout">
<header>
<RouterView name="header" />
</header>
<aside>
<RouterView name="sidebar" />
</aside>
<main>
<RouterView /> <!-- Default view -->
</main>
<footer>
<RouterView name="footer" />
</footer>
</div>
</template>๐ Basic Configuration โ
Route Configuration with Named Views โ
// router/index.js
const router = createRouter({
routes: [
{
path: '/',
components: {
default: Home, // Renders in <RouterView />
header: AppHeader, // Renders in <RouterView name="header" />
sidebar: AppSidebar, // Renders in <RouterView name="sidebar" />
footer: AppFooter // Renders in <RouterView name="footer" />
}
},
{
path: '/dashboard',
components: {
default: Dashboard,
header: DashboardHeader,
sidebar: DashboardSidebar,
footer: DashboardFooter
}
}
]
})Lazy Loading with Named Views โ
const routes = [
{
path: '/',
components: {
default: () => import('./views/Home.vue'),
header: () => import('./components/AppHeader.vue'),
sidebar: () => import('./components/AppSidebar.vue'),
footer: () => import('./components/AppFooter.vue')
}
}
]๐ง Advanced Techniques โ
Example 1: Dashboard with Dynamic Sidebar โ
<template>
<div class="dashboard-layout">
<!-- Top navigation -->
<RouterView name="header" />
<div class="dashboard-content">
<!-- Sidebar with context-aware navigation -->
<aside class="dashboard-sidebar">
<RouterView name="sidebar" />
</aside>
<!-- Main content area -->
<main class="dashboard-main">
<RouterView />
</main>
<!-- Right sidebar for additional info -->
<aside class="dashboard-rightbar">
<RouterView name="rightbar" />
</aside>
</div>
<!-- Footer with status information -->
<footer class="dashboard-footer">
<RouterView name="footer" />
</footer>
</div>
</template>
<script setup>
// This component serves as the layout container
// Individual views are configured in the router
</script>
<style scoped>
.dashboard-layout {
min-height: 100vh;
display: flex;
flex-direction: column;
}
.dashboard-content {
display: grid;
grid-template-columns: 250px 1fr 300px;
grid-template-areas: "sidebar main rightbar";
flex: 1;
gap: 1rem;
padding: 1rem;
}
.dashboard-sidebar {
grid-area: sidebar;
background: #f8f9fa;
border-radius: 8px;
padding: 1rem;
}
.dashboard-main {
grid-area: main;
background: white;
border-radius: 8px;
padding: 1.5rem;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.dashboard-rightbar {
grid-area: rightbar;
background: #f8f9fa;
border-radius: 8px;
padding: 1rem;
}
.dashboard-footer {
background: #343a40;
color: white;
padding: 1rem;
text-align: center;
}
@media (max-width: 768px) {
.dashboard-content {
grid-template-columns: 1fr;
grid-template-areas:
"sidebar"
"main"
"rightbar";
}
}
</style>Route Configuration for Dashboard โ
// router/dashboard.js
const dashboardRoutes = [
{
path: '/dashboard',
components: {
default: () => import('./views/Dashboard/Overview.vue'),
header: () => import('./components/Dashboard/Header.vue'),
sidebar: () => import('./components/Dashboard/Sidebar.vue'),
rightbar: () => import('./components/Dashboard/StatsPanel.vue'),
footer: () => import('./components/Dashboard/Footer.vue')
},
meta: { requiresAuth: true }
},
{
path: '/dashboard/analytics',
components: {
default: () => import('./views/Dashboard/Analytics.vue'),
header: () => import('./components/Dashboard/Header.vue'),
sidebar: () => import('./components/Dashboard/Sidebar.vue'),
rightbar: () => import('./components/Dashboard/AnalyticsPanel.vue'),
footer: () => import('./components/Dashboard/Footer.vue')
},
meta: { requiresAuth: true }
},
{
path: '/dashboard/settings',
components: {
default: () => import('./views/Dashboard/Settings.vue'),
header: () => import('./components/Dashboard/Header.vue'),
sidebar: () => import('./components/Dashboard/SettingsSidebar.vue'),
rightbar: () => import('./components/Dashboard/SettingsPanel.vue'),
footer: () => import('./components/Dashboard/Footer.vue')
},
meta: { requiresAuth: true, requiresAdmin: true }
}
]๐ ๏ธ Practical Examples โ
Example 2: E-commerce Product Page โ
<template>
<div class="product-page">
<!-- Product header with breadcrumb and actions -->
<RouterView name="header" />
<div class="product-content">
<!-- Product images gallery -->
<aside class="product-gallery">
<RouterView name="gallery" />
</aside>
<!-- Main product information -->
<main class="product-info">
<RouterView />
</main>
<!-- Purchase sidebar -->
<aside class="product-purchase">
<RouterView name="purchase" />
</aside>
</div>
<!-- Product details tabs -->
<section class="product-details">
<RouterView name="details" />
</section>
<!-- Related products -->
<section class="related-products">
<RouterView name="related" />
</section>
</div>
</template>
<style scoped>
.product-page {
max-width: 1200px;
margin: 0 auto;
padding: 1rem;
}
.product-content {
display: grid;
grid-template-columns: 400px 1fr 300px;
gap: 2rem;
margin: 2rem 0;
}
.product-gallery {
/* Gallery styles */
}
.product-info {
/* Info styles */
}
.product-purchase {
/* Purchase sidebar styles */
}
.product-details {
margin: 2rem 0;
}
.related-products {
margin: 2rem 0;
}
@media (max-width: 768px) {
.product-content {
grid-template-columns: 1fr;
gap: 1rem;
}
}
</style>Route Configuration for Product Page โ
const productRoutes = [
{
path: '/products/:id',
components: {
default: () => import('./views/Product/ProductInfo.vue'),
header: () => import('./components/Product/ProductHeader.vue'),
gallery: () => import('./components/Product/ProductGallery.vue'),
purchase: () => import('./components/Product/PurchaseSidebar.vue'),
details: () => import('./components/Product/ProductDetails.vue'),
related: () => import('./components/Product/RelatedProducts.vue')
},
props: {
default: true, // Pass route params as props to default component
header: true,
gallery: true,
purchase: true,
details: true,
related: true
}
}
]๐ Advanced Patterns โ
Nested Named Views โ
Combine named views with nested routes for maximum flexibility:
const complexRoutes = [
{
path: '/admin',
component: AdminLayout,
children: [
{
path: 'users',
components: {
default: UserList,
sidebar: UserFilters,
toolbar: UserActions
},
children: [
{
path: ':userId',
components: {
default: UserDetail,
sidebar: UserProfile,
toolbar: UserEditActions
}
}
]
}
]
}
]Dynamic Component Selection โ
<template>
<div class="dynamic-layout">
<RouterView :name="currentViewName" />
</div>
</template>
<script setup>
import { computed } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const currentViewName = computed(() => {
// Determine which view to show based on route or state
return route.meta.viewName || 'default'
})
</script>๐ Best Practices โ
โ Do โ
- Plan Layout Structure: Design your layout before implementing
- Use Semantic Names: Choose meaningful view names
- Keep Components Focused: Each view should have a single responsibility
- Test Responsive Behavior: Ensure layouts work on different screen sizes
- Document View Relationships: Document how views work together
โ Don't โ
- Overcomplicate: Avoid too many named views in one route
- Ignore Performance: Be mindful of lazy loading strategies
- Forget Mobile: Test on mobile devices
- Mix Concerns: Keep business logic separate from layout concerns
๐ Related Features โ
- RouterView Component: The foundation of named views functionality
- Nested Routes: Combine with named views for complex hierarchies
- Route Meta Fields: Store view configuration information
- Component Props: Pass data to named view components
๐ก Pro Tip
Combine named views with Vue's `provide/inject` API to share state between different view components without prop drilling, creating truly independent but coordinated view sections!
Ready for complex layouts? Start implementing named views to create sophisticated, multi-component application structures that provide excellent user experiences! ๐ฏ