DEV Community

Cover image for Creating Linkable Tabs in Next.js - The Easy Way!
Amr Tawfik
Amr Tawfik

Posted on

Creating Linkable Tabs in Next.js - The Easy Way!

Next.js is a powerful React framework that makes it easy to build and deploy server-side rendered React applications. One of the many features that Next.js provides is the ability to easily create linkable tabs.

In this article, we'll explore how to create linkable tabs in Next.js using the built-in Link component and the styled-jsx library. We'll also look at how to handle the active state of the tabs and make the tabs look like they're part of a traditional tabbed interface.

Creating the Tabs

The first thing we need to do is create the tabs themselves. We'll do this using the Link component from Next.js.

Each Link component will take an href prop which will be the URL that the tab will link to. We'll also give each Link a className of "tab" so that we can style them later.

const Tab1 = () => (
  <Link href="/tab1" className="tab">
    Tab 1
  </Link>
);

const Tab2 = () => (
  <Link href="/tab2" className="tab">
    Tab 2
  </Link>
);
Enter fullscreen mode Exit fullscreen mode

Now that we have our tabs, we need to style them. We'll do this using the styled-jsx library.

First, we'll create a global style sheet that will style our tabs. We'll give the tabs a width of 100% and some basic styles for the unselected state.

// Global stylesheet

const styles = (
  <style jsx global>{`
    .tab {
      display: inline-block;
      width: 100%;
      padding: 10px;
      border: 1px solid #ccc;
      border-bottom: none;
      text-align: center;
      cursor: pointer;
    }

    .tab:hover {
      background: #f0f0f0;
    }
  `}</style>
);
Enter fullscreen mode Exit fullscreen mode

Next, we'll create a style sheet for the selected state of the tabs. We'll give the tabs a different color and make the bottom border thicker.

// Selected state stylesheet

const selectedStyles = (
  <style jsx>{`
    .tab.selected {
      border-color: #aaa;
      border-width: 2px;
      background: #fff;
    }
  `}</style>
);
Enter fullscreen mode Exit fullscreen mode

Now that we have our stylesheets, we need to apply them to our tabs. We'll do this using the jsx prop on the Link component.

const Tab1 = () => (
  <Link
    href="/tab1"
    className="tab"
    jsx={[styles, selectedStyles]}
  >
    Tab 1
  </Link>
);

const Tab2 = () => (
  <Link
    href="/tab2"
    className="tab"
    jsx={styles}
  >
    Tab 2
  </Link>
);
Enter fullscreen mode Exit fullscreen mode

Now our tabs are styled and we can move on to handling the active state.

Handling the Active State

There are a few different ways that we can handle the active state of our tabs. In this section, we'll explore two of them.

The first method is to use the built-in router from Next.js. This method is simple and easy to use, but it has a few drawbacks. The biggest drawback is that it will only work with browser history API-enabled browsers.

The second method is to use a custom solution that uses the URL query string. This method is a bit more complex, but it will work with all browsers.

Using the built-in router

If we want to use the built-in router from Next.js, we need to wrap our tabs in a Router component. We also need to give each tab a unique key so that the router can keep track of them.

const Tab1 = () => (
  <Router>
    <Link
      key="tab1"
      href="/tab1"
      className="tab"
      jsx={[styles, selectedStyles]}
    >
      Tab 1
    </Link>
  </Router>
);

const Tab2 = () => (
  <Router>
    <Link
      key="tab2"
      href="/tab2"
      className="tab"
      jsx={styles}
    >
      Tab 2
    </Link>
  </Router>
);
Enter fullscreen mode Exit fullscreen mode

Now that our tabs are wrapped in a Router component, the built-in router will take care of the active state for us.

Using the URL query string

If we want to use the URL query string to handle the active state, we need to write a custom React hook that parses the query string and returns the active tab.

// useActiveTab.js

import { useRouter } from "next/router";

export default function useActiveTab() {
  const { query } = useRouter();
  const activeTab = query.activeTab || "tab1";
  return activeTab;
}
Enter fullscreen mode Exit fullscreen mode

Now that we have our custom hook, we can use it in our tabs to add the active class to the correct tab.

import useActiveTab from "../hooks/useActiveTab";

const Tab1 = () => {
  const activeTab = useActiveTab();

  return (
    <Link
      href="/tab1"
      className={`tab ${activeTab === "tab1" && "selected"}`}
      jsx={[styles, selectedStyles]}
    >
      Tab 1
    </Link>
  );
};

const Tab2 = () => {
  const activeTab = useActiveTab();

  return (
    <Link
      href="/tab2"
      className={`tab ${activeTab === "tab2" && "selected"}`}
      jsx={styles}
    >
      Tab 2
    </Link>
  );
};
Enter fullscreen mode Exit fullscreen mode

Now our tabs will correctly update the active state when the query string is updated.

Making the Tabs Look Like They're Part of a Tabbed Interface

If we want our tabs to look like they're part of a traditional tabbed interface, we need to add some additional styles.

First, we'll add a style sheet that styles the tab content. We'll give the content a width of 100% and make it hidden by default.

// Tab content stylesheet

const contentStyles = (
  <style jsx>{`
    .tab-content {
      display: none;
      width: 100%;
      padding: 20px;
      border: 1px solid #ccc;
      background: #fff;
    }
  `}</style>
);
Enter fullscreen mode Exit fullscreen mode

Next, we'll add a style sheet for the selected state of the tab content. We'll make the content visible when it's selected.

// Selected state stylesheet

const selectedContentStyles = (
  <style jsx>{`
    .tab-content.selected {
      display: block;
    }
  `}</style>
);
Enter fullscreen mode Exit fullscreen mode

Now we need to apply our stylesheets to our tab content. We'll do this using the jsx prop on the Link component.

const Tab1Content = () => (
  <div
    className="tab-content"
    jsx={[contentStyles, selectedContentStyles]}
  >
    Tab 1 content
  </div>
);

const Tab2Content = () => (
  <div
    className="tab-content"
    jsx={contentStyles}
  >
    Tab 2 content
  </div>
);
Enter fullscreen mode Exit fullscreen mode

Finally, we need to update our tabs to render the correct tab content when they're clicked. We'll do this using the built-in router from Next.js.

const Tab1 = () => (
  <Router>
    <Link
      key="tab1"
      href="/tab1"
      className="tab"
      jsx={[styles, selectedStyles]}
    >
      Tab 1
    </Link>
    <Tab1Content />
  </Router>
);

const Tab2 = () => (
  <Router>
    <Link
      key="tab2"
      href="/tab2"
      className="tab"
      jsx={styles}
    >
      Tab 2
    </Link>
    <Tab2Content />
  </Router>
);
Enter fullscreen mode Exit fullscreen mode

Now our tabs look like they're part of a traditional tabbed interface and we can easily switch between them.

Conclusion

In this article, we've explored how to create linkable tabs in Next.js using the built-in Link component and the styled-jsx library. We've also looked at how to handle the active state of the tabs and make the tabs look like they're part of a traditional tabbed interface.

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.