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
Mobile View
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
Next, we’ll install Chakra UI and some dependencies.
npm i @chakra-ui/react @emotion/react lucide-react
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>
);
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:
- Logo → Branding text or an image.
- Menu Links → Navigation links and a call-to-action button, horizontal on desktop, vertical on mobile.
- 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;
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;
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;
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;
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)