How to create a tabs component in Vue 3

Derrick Otte
4 min readNov 16, 2021
Gif of tab component in action, navigating through the different tabs.

With the removal of this.$children from Vue 2, I was at a complete loss on how to create a tabs component in Vue 3. I initially thought about using Template refs, which you can access through this.$refs in Vue’s new composition API to achieve a similar outcome, but I’m new to the composition API, and Vue 3’s documentation specifically says not to use this.$refs as a reactive property.

So I started to think of a different way to create tabs in my project, a way that I should have thought about from the beginning — just use the Vue router and nested routes!

Before continuing, I’m assuming you have some experience with Vue 2/3, and JavaScript. If you’re not familiar with any of those, I would encourage you to check out Vue 2 and Vue 3’s documentation before following along. Additionally, you need to have NPM installed on your computer so that you can install Vue CLI, the command line tool I’ll be using in this guide.

Step 1: Create an empty Vue 3 Project

Now, let’s get started. First, with Vue CLI installed, create a new project:

vue create tabs-example

You’ll be prompted to pick a preset. In Vue CLI v.4.5.x, I only have two available - Vue 2 and Vue 3. Choose Vue 3, which looks like:

Default (Vue 3) ([Vue 3] babel, eslint)

Now, you have a boilerplate Vue project. In order to create a tabs component, you’re going to need to have Vue router installed. Vue router will be the power behind users navigating between routes (or pages) in your application.

Step 2: Add Vue Router

More so, it will be the power behind tab navigation in your application: allowing users to navigate in between nested routes (tabs) within parent routes (pages). To install Vue router through Vue CLI, run this command:

vue add router

It will ask you if you want to use history mode, go ahead and decline. Now if you run npm run serve, and head to localhost:8080 in your browser, you should see the boilerplate vue application, with two routes: Home and About.

Screenshot of default Vue application with two new routes: Home and About.

Step 3: Creating Tabs through Nested Routes

Now comes the exciting part — creating tabs. Inside of your /views directory in your project, create two new components: History and Contact. If you need an empty component template, I’ve created a gist that I use pretty frequently for myself that you can copy:

Once the components are created, open up /src/router/index.js in your project, which is your router file. To the /about route, you’re going to add a new children: [] argument, and add the new History and Contact components to it. Your file should look like this:

At this point, you’re almost finished. You’ve created two new components, and you’ve set up routing for them. All that’s left to turn them into tabs is to setup a nested <router-view> template inside of the parent /about page, and add some links through <router-link>:

Your finished About.vue should look like this.

Router-view and router-link are both provided directly by Vue Router. Router-view injects the current matched component in your routes file to the route you visit in the browser. Router-link just wraps an anchor tag around the route you define to go to.

Now, if you reload localhost:8080, you should see something that looks like this:

Screenshot of tabs component without styling added

Step 4: Add Styling

Viola, you have a tabs component! But this doesn’t really look like tabs. With no styling, this doesn’t really look like anything useful. But that is easily fixable with some css added to the About component’s <style>:

With styles added, refresh localhost:8080, and you should see a definitive tabs component, styled and all:

Screenshot of finished tabs component with styling added

Now you have tabs, and you can easily add more tabs through additional nested routes. Or you could create nested routes on a different parent route, keeping the styles the same to make the tabs look consistent.

If you’d like to see the full source code for this small project, you can check out the Github repo here.

--

--