Problem Statement
In a Vue application I needed to have a screen (on path /department/:departmentId) where I need to show one common header containing a selector between three tabs and then a body section which would show different content based on which tab was selected. And each tab would be associated with a different sub-path:
- "Overview" ->
/department/:id - "Members" ->
/department/:id/members - "Clients" ->
/department/:id/clients
It also had to be implemented that navigating directly to any of the sub-paths should open the correct page.
Solution Approach
I needed to use <router-view /> and the nested routes feature from vue-router.
Configuring the router
Here is how we configured the routes:
const routes = [
{
path: '/department/:id',
component: () => import('@/views/department/Index.vue'),
children: [
{ path: '', name: 'department-overview', component: () => import('@/views/department/TabOverview.vue') },
{ path: 'members', name: 'department-members', component: () => import('@/views/department/TabMembers.vue') },
{ path: 'clients', name: 'department-clients', component: () => import('@/views/department/TabClients.vue') },
],
}
];
Notice that we haven't specified any extra path for the "Overview" tab. This is by design and will be explained later.
Setting up the root view
And the contents of Index.vue (containing the overall page contents) looked something like this:
<script setup lang="ts"></script>
<template>
<nav>
<router-link :to="{ name: 'department-overview' }">Overview</router-link>
<router-link :to="{ name: 'department-members' }">Members</router-link>
<router-link :to="{ name: 'department-clients' }">Clients</router-link>
</nav>
<main>
<router-view />
</main>
</template>
Individual tab contents
Each tab's file turns out pretty simple, something like this:
<script setup lang="ts"></script>
<template>
<p>Overview/Members/Clients</p>
</template>
Combining the ingredients
The reason we did not specify an extra path in our router is that we need to show it directly when /department/:id is opened. Now when we go to /department/:id we see the header bar showing the three tab links and the contents of the "Overview" tab under it. Clicking on any other tab shows that content below the header bar, also the url gets updated.
This gives us clean URLs, browser history support, the ability to persist tab-selection across page refresh, and the ability to directly navigate to any tab via URL. No manual state management is required to determine what content to show, it will automatically update based on the URL.