DEV Community

Cover image for Responsive Navbar in React using shadcn/ui and Tailwind CSS
Shaikat Haque
Shaikat Haque

Posted on

Responsive Navbar in React using shadcn/ui and Tailwind CSS

Source Code: https://github.com/shaikathaque/navbar-responsive-shadcn-ui-example

Live demo: https://navbar-responsive-shadcn-ui-example.netlify.app/

Overview

While there are many difference ways to build a responsive navbar in React, this article will utilize Tailwind CSS for shadcn/ui.

This post is influenced by the responsive navbar in shadcn/ui’s website, which is open source. Shadcn/ui has become a very popular choice in the React ecosystem for building UIs that are beautiful, accessible, and customizable.

In order to emphasize the core parts of the the navbar, there will be less focus on styling and advanced functionality.


Key Components

  1. Site Header component, which holds both mobile and main navbar components.
  2. Main navbar component, visible on medium screen sizes and above.
  3. Mobile navbar component, visible on small screen sizes, and toggles open a sheet as a menu.

1. Site Header Component

Add a SiteHeader component in the root of our app, in this case, App.tsx. The SiteHeader component will contain both our main and and mobile navbar components.

// App.tsx
import SiteHeader from '@/components/siteHeader';

function App() {
  return (
    <div className="flex min-h-screen flex-col">
      <SiteHeader />
      {/* Body components go here */}
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

In the SiteHeader.tsx, we can include both the mobile and desktop nav components. Within each of those, we will then add tailwind-css classes to control their visibility.

// SiteHeader.tsx
import MainNav from './mainNav';
import MobileNav from './mobileNav';

export default function SiteHeader() {
  return (
    <header className="w-full border-b">
      <div className="flex h-14 items-center px-4">
        <MainNav />
        <MobileNav />
      </div>
    </header>
  );
}
Enter fullscreen mode Exit fullscreen mode

2. Main Nav Component

The MainNav component is what will be visible in medium screen sizes and above.

// MainNav.tsx
import { Button } from './ui/button';

const mainNavItems = ['A', 'B', 'C'];

export default function MainNav() {
  return (
    <div className="mr-4 hidden gap-2 md:flex">
      {mainNavItems.map((item, index) => (
        <Button key={index} variant="link">
          {item}
        </Button>
      ))}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Main Navbar on large screen size

There are 2 key classes that help achieve this: hidden and md:flex.

The hidden sets display: none to the div by default. However, when the screen size is medium (768 pixels) or above, md:flex sets display: flex, making the div visible.


3. Mobile Nav Component

The MobileNav component will only be visible in screen sizes smaller than medium, in contrast to the MainNav which is visible in medium screens and larger.

// MobileNav.tsx
import { useState } from 'react';
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet';
import { Button } from '@/components/ui/button';
import { Menu as MenuIcon } from 'lucide-react';

const mobileItems = ['A', 'B', 'C'];

export default function MobileNav() {
  const [open, setOpen] = useState(false);

  return (
    <Sheet open={open} onOpenChange={setOpen}>

      {/* This button will trigger open the mobile sheet menu */}
      <SheetTrigger asChild>
        <Button variant="ghost" size="icon" className="md:hidden">
          <MenuIcon />
        </Button>
      </SheetTrigger>

      <SheetContent side="left"> 
        <div className="flex flex-col items-start">
          {mobileItems.map((item, index) => (
            <Button
              key={index}
              variant="link"
              onClick={() => {
                setOpen(false);
              }}
            >
              {item}
            </Button>
          ))}
        </div>
      </SheetContent>

    </Sheet>
  );
}
Enter fullscreen mode Exit fullscreen mode

Mobile Navbar on small screen size

Mobile menu opened

The key class here is the md:hidden on the Button component within the SheetTrigger.

This makes the menu trigger button visible by default, but will have display: none when the screen size is md (768 pixels) and larger.

The SheetContent component’s side prop allows you to choose which direction the sheet will open from.


Parting Thoughts

The React ecosystem is changing really quickly. A couple years from now, there might be a different recommended way to build a mobile navbar. However, the fundamentals and underlying concepts stay the same.

If you have any feedback about this post or if anything is unclear, please reach out to me and I’ll do my best to help.

Top comments (0)