Creating a Tabs component with Next.js

Ugonna Thelma
Backticks & Tildes
Published in
6 min readMar 20, 2019

Hey, It’s me again!

I’ve been asked by a couple of people new to Next.js how to implement tabs within a page. If you’re already familiar with Next.js, you’ll know that to create a page, you simply create a file in your pages folder but not a lot of people know how to implement tabs within a particular page using Next.js.

Before we start this tutorial, Here are three reasons why I absolutely love Next.js:

  • It’s so easy to setup
  • It performs automatic code splitting
  • Routing is extremely simple

You can read more about Next.js here

For this tutorial, I ’ll be using React to build out our component and Emotion for styling. If you’re familiar with styled-components, Emotion is very similar so you can still follow along. I’ll also be using Yarn for package management.

Step 1 — Install Packages

Install the packages we need with the command below in your terminal

yarn add react react-dom next @emotion/core @emotion/styled

Once you have these installed, your package.json file should contain the following dependencies and scripts:

"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@emotion/core": "^10.0.7",
"@emotion/styled": "^10.0.7",
"next": "^8.0.3",
"react": "^16.8.4",
"react-dom": "^16.8.4"
}

Step 2 — Folder Structure

Once your packages are installed, the next thing to do is create folders for your page layouts, pages, and components. Also, create a file for your styles. Your folder structure should look like this

.
├── components
├── layouts
├── node_modules
├── package.json
├── pages
├── styles.js
└── yarn.lock

Step 3 — Build Page Layout

The next step is to define how our pages will look. We want all our pages to have a navigation menu and the content of each page to be displayed below the navigation menu.

To do this, we’ll create index.js file in the layouts folder, then createNav and PageBody elements in our styles.js file using emotion.

import styled from "@emotion/styled"export const Nav = styled("div")`
& > * {
margin-left: 1em;
color: white;
}
background: black;
padding: 1em;
height: 2em;
display: flex;
align-items: center;
`
export const PageBody = styled("div")`
width: 100%;
height: 100%;
padding: 2em;
`

Import these into the layouts index file, and include our desired links within the Nav tags using Next.js Link component. Our layout component will also take children as props so we can display our page content within the PageBody tags.

layouts/index.js

Step 4 — Create pages

Now that we’ve created the layout, it’s time to create the home page and another page which you can name anything you like. I’ll call mine page-two. The point of the layout is to have a common arrangement throughout the entire application without creating duplicate elements in each page.

All we have to do is import the layout component into each page and wrap it around our component and no matter the route we navigate to, we will always see the navigation bar.

Now, let’s create theindex.js and page-two.js files in the pages folder. The home page is going to contain our Tabs Component which we’ll create later. For now, we’ll just have a placeholder text.

pages/index.js
pages/page-two.js

Run your application with the command below

yarn run dev

After running your application, if you navigate to http://localhost:3000, you should see the navigation bar and the contents of each page.

pages/index.js
pages/page-two.js

You’ll notice that the navigation bar doesn’t extend fully to the sides of the page.

To solve this, we have to set the margin and padding of the HTML body to zero. We can also set the font and any other style we want to apply across the entire app.

There are two ways we can do this in our layout component. We can use Emotion’s Global component in our layout component or Next.js Head component. If you’re using styled-components, it has a createGlobalStyle function that can be used to achieve this.

Using Emotion’s Global component
Using Next.js Head component

The white space around the navigation bar should disappear after using any of these methods.

Step 5 — Create tabs component

Now, we’re going to create a basic tabs component with two tabs Tab 1 and Tab 2

Create a Tabs.js file in the components folder and create the following elements in your styled.js file.

TabContainer — This will contain all the elements in the tabs component.

Tab — This is what we will click in order to switch tabs. The tab will take selected prop. So we know which tab is currently selected and what background colour it should have.

TabHead — This will contain the tabs.

TabBody — This will contain the content for each tab.

export const TabHead = styled("div")`
border-bottom: 1px solid black;
display: flex;
background: black;
`
export const TabContainer = styled("div")`
width: 30em;
height: 30em;
webkit-box-shadow: -1px 0px 5px 0px rgba(184, 184, 184, 1);
-moz-box-shadow: -1px 0px 5px 0px rgba(184, 184, 184, 1);
box-shadow: -1px 0px 5px 0px rgba(184, 184, 184, 1);
`
export const TabBody = styled(PageBody)`
height: 100%;
`
export const Tab = styled("div")`
padding: 1em;
background: ${({ selected }) => (selected ? "grey" : "black")};
* {
color: white;
}
`

Next, import these elements into Tabs.js

import React from "react"
import { TabHead, TabContainer, TabBody, Tab } from "../styles"
const Tabs = () => {
return (
<TabContainer>
<TabHead>
<Tab />
<Tab />
</TabHead>
<TabBody />
</TabContainer>
)
}
export default Tabs

Inside each Tab we need to add a link with the tab name, we’ll use the Next.js Link component to do this. The Link component takes a prop href, that can either be a string or an object containing pathname key. We’ll need to import the Link component into the Tabs component

import Link from “next/link”

then use it like this

<TabHead>
<Tab>
<Link href={{ pathname: "/" }}>
<a>Tab 1</a>
</Link>
</Tab>
<Tab>
<Link href={{ pathname: "/" }}>
<a>Tab 2</a>
</Link>
</Tab>
</TabHead>

The pathname is the same because we still want to be on the same page when switching to different tabs. But how do we control which tab content to display when you click on any of them? By using queries.

The Link component can also take aquery key. Using the query value, we can let our component know which content to display.

<TabHead>
<Tab>
<Link href={{ pathname: "/", query: { tab: "1" } }}>
<a>Tab 1</a>
</Link>
</Tab>
<Tab>
<Link href={{ pathname: "/", query: { tab: "2" } }}>
<a>Tab 2</a>
</Link>
</Tab>
</TabHead>

Remember our Tab element takes selected prop, which should be a boolean. So for each Tab, we need to check that the current query is equal to 1 and 2 respectively. For scenarios where there’s no query then we’ll default to Tab 1.

To access the pathname and query, we need to wrap the Tabs component with Next.js withRouter higher order component. After doing this, we can extract tab from the route query and use it to check the selected tab.

We’ll create constants isTabOne and isTabTwo to hold this data.

Tabs component wrapped in withRouter HOC

When you run the application, you should see this.

Tabs in Home page

Finally, we can render content for each tab using the constants we created.

<TabBody>
{isTabOne &&
<React.Fragment>This is tab one content</React.Fragment>
}
{isTabTwo &&
<React.Fragment>This is tab two content</React.Fragment>
}
</TabBody>

Our final product should look like this.

Final product

C’est Fini! Here’s a link to the source code on Github.

If you have any questions, leave a comment

--

--

Ugonna Thelma
Ugonna Thelma

Written by Ugonna Thelma

Software Engineer, UI Designer, Logo Designer, Childrens book illustrator :)