DEV Community

Cover image for Build a Responsive NavBar in React with Chakra UI v3
Anderson Osayerie
Anderson Osayerie

Posted on

Build a Responsive NavBar in React with Chakra UI v3

Introduction

Every landing page or app needs a robust navigation bar that works across all screen sizes. With Chakra UI v3, we can build a fully responsive NavBar in React with minimal code, while leveraging Chakra’s composable components, theming, and responsive props.

Why Chakra UI, you might ask?

Here's how I actually ended up with Chakra UI: I recently joined a new team, and they were already deep into using Chakra for their project. I had my own preferred stack, but the team needed consistency. So I dove in. And wow, was I pleasantly surprised.

What We're Building

We'll create a navbar that:

  • Collapses into a hamburger menu on mobile devices
  • Displays all navigation items on desktop
  • Includes a logo, navigation links, and a call-to-action button

Desktop View

Navbar on desktop

Mobile View

Navbar on mobile

Installation

Let’s start a new React project using Vite, but create-react-app or Next.js also works:

npm create vite@latest chakra-navbar -- --template react-ts
cd chakra-navbar
npm install
Enter fullscreen mode Exit fullscreen mode

Next, we’ll install Chakra UI and some dependencies.

npm i @chakra-ui/react @emotion/react lucide-react
Enter fullscreen mode Exit fullscreen mode

For setting up Chakra UI with React, we'll need to wrap our app with the ChakraProvider and a custom theme, or the default system theme. You can check the documentation for full installation instructions.

// main.tsx

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { ChakraProvider, defaultSystem } from "@chakra-ui/react";

import App from "./App.tsx";

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <ChakraProvider value={defaultSystem}>
      <App />
    </ChakraProvider>
  </StrictMode>
);
Enter fullscreen mode Exit fullscreen mode

Building the Navbar Components

Let's break our navbar into smaller, manageable components. This approach makes our code cleaner and easier to maintain.

Our NavBar will have three parts:

  1. Logo → Branding text or an image.
  2. Menu Links → Navigation links and a call-to-action button, horizontal on desktop, vertical on mobile.
  3. Mobile Drawer → A hamburger button and slide-in drawer for smaller screens.

We’ll compose these inside a Flex container that adapts at breakpoints.

Logo Component

The Logo is the brand identity of the NavBar. It’s often the first thing users notice, so we want it to be simple yet clear.

In this tutorial, we’ll just use a styled text element as our logo, but you could easily swap it out for an actual image.

Here’s the component:

import { Box, Text } from "@chakra-ui/react";

const Logo = () => {
  return (
    <Box>
      <Text fontSize="lg" fontWeight="bold" color="blue.600">
        Logo
      </Text>
      {/* Or use an actual image */}
      {/* <Image src="/logo.png" alt="Logo" height="40px" /> */}
    </Box>
  );
};

export default Logo;
Enter fullscreen mode Exit fullscreen mode

The Menu Links

It’s the part of the NavBar that includes the navigation links and a call-to-action button.

Instead of writing raw tags every time, we’ll define our navigation items in a simple array and map through them. Each item is styled consistently and gets hover transitions for a smooth effect.

Here’s how it looks in our component:

import { HStack, VStack, Link, Button } from "@chakra-ui/react";

const links = [
  { name: "Home", href: "#home" },
  { name: "About", href: "#about" },
  { name: "Services", href: "#services" },
  { name: "Contact", href: "#contact" },
];

const MenuLinks = ({ isMobile = false }) => {
  const LinkComponent = isMobile ? VStack : HStack;

  return (
    <LinkComponent gap={isMobile ? 4 : 8} align="center">
      {links.map((link) => (
        <Link
          key={link.name}
          href={link.href}
          fontWeight="medium"
          color="blue.600"
          _hover={{
            color: "blue.500",
            textDecoration: "underline",
          }}
          transition="color 0.2s ease"
        >
          {link.name}
        </Link>
      ))}

      <Button
        bg="blue.600"
        color="white"
        size="sm"
        borderRadius="full"
        px={6}
        _hover={{
          transform: "translateY(-2px)",
          shadow: "lg",
        }}
        transition="all 0.2s ease"
      >
        Get Started
      </Button>
    </LinkComponent>
  );
};

export default MenuLinks;
Enter fullscreen mode Exit fullscreen mode

As you can see, the component dynamically switches between VStack and HStack depending on the screen size. On mobile, the navigation items are stacked vertically, while on desktop, they are aligned horizontally.

This is controlled by the optional isMobile prop. We also fine-tune the gap to control spacing and alignment. At the end of the navigation links, we include a “Get Started” call-to-action button.

Mobile Drawer Component

On smaller screens, we don’t want the links taking up horizontal space. Instead, we replace them with a hamburger button. When clicked, this button opens a full-screen Drawer that slides in with the menu items.

For this, we’ll use Chakra UI’s Drawer component. You can check the Drawer docs for more details, but here’s a simple MobileDrawer component for our nav:

import {
  useDisclosure,
  Drawer,
  Button,
  Portal,
  CloseButton,
  Icon,
} from "@chakra-ui/react";
import { Menu } from "lucide-react";
import Logo from "./Logo";
import MenuLinks from "./MenuLinks";

const MobileDrawer = () => {
  const { open, onToggle } = useDisclosure();

  return (
    <Drawer.Root open={open} onOpenChange={onToggle} size="full">
      <Drawer.Trigger asChild>
        <Button variant="outline" size="sm">
          <Icon color="blue.600">
            <Menu />
          </Icon>
        </Button>
      </Drawer.Trigger>
      <Portal>
        <Drawer.Backdrop />
        <Drawer.Positioner>
          <Drawer.Content>
            <Drawer.Header>
              <Drawer.Title>
                <Logo />
              </Drawer.Title>
            </Drawer.Header>
            <Drawer.Body>
              <MenuLinks isMobile />
            </Drawer.Body>
            <Drawer.CloseTrigger asChild>
              <CloseButton size="md" />
            </Drawer.CloseTrigger>
          </Drawer.Content>
        </Drawer.Positioner>
      </Portal>
    </Drawer.Root>
  );
};

export default MobileDrawer;
Enter fullscreen mode Exit fullscreen mode

This component uses Chakra’s useDisclosure hook to handle opening and closing. We add the Logo in the header and reuse MenuLinks (this time with the isMobile prop) inside the drawer. The close button provides a simple way to exit.

Putting It All Together

Now that we have Logo, MenuLinks, and MobileDrawer, let’s combine them into our final NavBar.

import { Flex, Box } from "@chakra-ui/react";
import Logo from "./Logo";
import MenuLinks from "./MenuLinks";
import MobileDrawer from "./MobileDrawer";

function App() {
  return (
    <Flex
      as="nav"
      align="center"
      justify="space-between"
      wrap="wrap"
      gap={{ base: 8, lg: 16 }}
      px={{ base: 6, lg: 12 }}
      py={3}
      maxW={{ base: "full", xl: "1440px" }}
      mx="auto"
    >
      <Logo />

      {/* Desktop Menu */}
      <Box display={{ base: "none", md: "block" }}>
        <MenuLinks />
      </Box>

      {/* Mobile Drawer */}
      <Box display={{ base: "block", md: "none" }}>
        <MobileDrawer />
      </Box>
    </Flex>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Here, we conditionally render the navigation by placing MenuLinks inside a Box that only appears on desktop (md and above), while the MobileDrawer is wrapped in a Box that only displays on mobile (base).

Conclusion

We built a responsive navigation bar using Chakra UI, complete with:

  • A reusable Logo component.
  • A flexible MenuLinks component that adapts to desktop or mobile layouts.
  • A MobileDrawer that slides in on small screens.

With Chakra UI handling layout and styling, plus React’s component-based architecture, we end up with a clean, responsive NavBar.

I have attached a link to the code on github.

Top comments (0)