Top Bar Navigation
The TopBar component creates a clean and consistent header for your website. It includes a brand logo on the left, navigation links in the center, and user actions (avatar or Sign In button) on the right. Built with Tailwind CSS for Next.js and React.js projects, it helps you maintain a professional and user-friendly layout across all pages.
Top Bar preview
- With user is logged in

- With user is not logged in

Please install everything that's required
1. Setup codes
Before setup this component, you need setup some common components
1.1 Create all constant URLs
Create a new file constants/routes.ts, this file include all routes URL and Navigation links (for both TopBar and Footer component).
jsexport const ROUTES = { homePage: "/", signIn: "/signin", signUp: "/signup", account: "/account", }; export const NAVIGATION_LINKS = [ { name: "My Projects", path: ROUTES.myProjects }, { name: "About Me", path: ROUTES.aboutMe }, { name: "Contact Me", path: ROUTES.contactMe }, ];
You can change this file base your links which you want to show.
1.2 Create App Logo component
Create a new file components/ui/AppLogo.tsx, this component to show the App logo on the left site of TopBar.
jsximport Image from "next/image"; import Link from "next/link"; import { ROUTES } from "@/constants/routes"; const AppLogo = (props: any) => { return ( <Link href={ROUTES.homePage}> <Image src="/images/app-logo.png" alt="App logo" width={200} height={50} {...props} /> </Link> ); }; export default AppLogo;
1.3 Create User interface
Create a new file types/user.d.ts, this file save the User interface (it represent for user who login your app)
jsexport interface IUser { firstName: string; lastName?: string; email: string; password?: string; image?: string; }
1.4 Create TopBar component
Create a new file components/layouts/common/TopBar/index.tsx, then paste the codes below
jsx"use client"; import { useEffect, useState } from "react"; import { usePathname } from "next/navigation"; import AppLogo from "@/components/ui/AppLogo"; import Button from "@/components/ui/Button"; import { Container } from "@/components/ui/Container"; import { NAVIGATION_LINKS, ROUTES } from "@/constants/routes"; import { IUser } from "@/types/user"; import { cn } from "@/utils/cn"; import AccountInfoButton from "./AccountInfoButton"; import MobileTopNavigation from "./MobileTopNavigation"; import PcNavLink from "./PcNavLink"; const TopNavigation = () => { const pathname = usePathname(); // TODO: You can add the function to get user session (or check user signin or not) const session = { user: { firstName: "Bien", lastName: "Anh", email: "bientuanh46@gmail.com", signUpBy: "credentials", }, }; // const session = null; const [isScrolled, setIsScrolled] = useState(false); useEffect(() => { const handleScroll = () => { setIsScrolled(window.scrollY > 0); }; window.addEventListener("scroll", handleScroll); return () => window.removeEventListener("scroll", handleScroll); }, []); const isHomepage = pathname === ROUTES.homePage; return ( <header className={cn( "fixed left-0 right-0 top-0 z-50 bg-white py-2 opacity-90 shadow-slate-900/5", !isHomepage ? "shadow-md" : isScrolled ? "shadow-md" : "", )} > <Container> <nav className="relative z-50 flex justify-between"> <div className="flex items-center md:gap-x-12"> <AppLogo /> <div className="hidden md:flex md:gap-x-6"> {NAVIGATION_LINKS.map((link) => { return ( <PcNavLink key={link.path} href={link.path}> {link.name} </PcNavLink> ); })} </div> </div> <div className="flex items-center gap-x-3 md:gap-x-3"> {session ? ( <AccountInfoButton accountInfo={session.user as IUser} /> ) : ( <> <div className="hidden md:block"> <Button variant="secondary" href={ROUTES.signIn}> Sign in </Button> </div> <Button href={ROUTES.signUp} className="hidden sm:inline"> <span>Sign up</span> </Button> </> )} <div className="-mr-1 md:hidden"> <MobileTopNavigation /> </div> </div> </nav> </Container> </header> ); }; export default TopNavigation;
1.5 Create Account Info Button component
Create a new file components/layouts/common/TopBar/AccountInfoBtn.tsx
jsximport Image from "next/image"; import Link from "next/link"; import { signOut } from "next-auth/react"; import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react"; import { ArrowRightStartOnRectangleIcon, Cog6ToothIcon } from "@heroicons/react/24/outline"; import { ROUTES } from "@/constants/routes"; import { IUser } from "@/types/user"; export default function AccountInfoButton({ accountInfo }: { accountInfo: IUser }) { return ( <Menu as="div" className="relative inline-block text-left"> <div> <MenuButton className={`inline-flex h-[38px] w-[38px] items-center justify-center gap-x-1.5 rounded-full ${accountInfo.image ? "bg-white" : "bg-primary"} px-[6px] py-[6px] text-sm font-semibold text-white shadow-sm ring-1 ring-inset ring-gray-300 hover:opacity-80`} > {accountInfo.image ? ( <Image src={accountInfo.image} alt="user image" layout="fill" objectFit="cover" className="rounded-full" /> ) : ( accountInfo.firstName.slice(0, 1).toUpperCase() )} </MenuButton> </div> <MenuItems transition className="absolute right-0 z-10 mt-2 w-56 origin-top-right divide-y divide-gray-100 rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 transition focus:outline-none data-[closed]:scale-95 data-[closed]:transform data-[closed]:opacity-0 data-[enter]:duration-100 data-[leave]:duration-75 data-[enter]:ease-out data-[leave]:ease-in" > <div className="px-4 py-3"> <p className="text-sm">Signed in as</p> <p className="truncate text-sm font-medium text-gray-900">{accountInfo.email}</p> </div> <div className="py-1"> <MenuItem> <Link href={ROUTES.account} className="flex justify-between px-4 py-2 text-sm text-gray-700 data-[focus]:bg-gray-100 data-[focus]:text-gray-900 data-[focus]:outline-none" > Account settings <Cog6ToothIcon className="size-5" /> </Link> </MenuItem> </div> <div className="py-1"> <MenuItem> <button onClick={(e) => { e.preventDefault(); signOut({ callbackUrl: ROUTES.homePage }); }} className="flex w-full items-center justify-between px-4 py-2 text-sm text-system-error data-[focus]:bg-gray-100 data-[focus]:text-system-error data-[focus]:outline-none" > Sign out <ArrowRightStartOnRectangleIcon className="size-5" /> </button> </MenuItem> </div> </MenuItems> </Menu> ); }
1.6 Create Mobile Navigation component
Create a new file components/layouts/common/TopBar/MobileNavigation.tsx
jsximport { Popover, PopoverBackdrop, PopoverButton, PopoverPanel } from "@headlessui/react"; import MobileNavIcon from "@/components/ui/icons/MobileNavIcon"; import { NAVIGATION_LINKS, ROUTES } from "@/constants/routes"; import MobileNavLink from "./MobileNavLink"; const MobileTopNavigation = () => { return ( <Popover> <PopoverButton className="ui-not-focus-visible:outline-none relative z-10 flex h-8 w-8 items-center justify-center" aria-label="Toggle Navigation" > {({ open }) => <MobileNavIcon open={open} />} </PopoverButton> <PopoverBackdrop transition className="fixed inset-0 bg-slate-300/50 duration-150 data-[closed]:opacity-0 data-[enter]:ease-out data-[leave]:ease-in" /> <PopoverPanel transition className="absolute inset-x-0 top-full mt-4 flex origin-top flex-col rounded-2xl bg-white p-4 text-lg tracking-tight text-slate-900 shadow-xl ring-1 ring-slate-900/5 data-[closed]:scale-95 data-[closed]:opacity-0 data-[enter]:duration-150 data-[leave]:duration-100 data-[enter]:ease-out data-[leave]:ease-in" > {NAVIGATION_LINKS.map((link) => { return ( <MobileNavLink key={link.path} href={link.path}> {link.name} </MobileNavLink> ); })} <> <hr className="m-2 border-slate-300/40" /> <MobileNavLink href={ROUTES.signIn}>Sign in</MobileNavLink> </> </PopoverPanel> </Popover> ); }; export default MobileTopNavigation;
1.7 Create PC Navigation Link component
Create a new file components/layouts/common/TopBar/PcNavLink.tsx
jsximport { cn } from "@/utils/cn"; const PcNavLink = ({ href, children, }: { href: string; children: React.ReactNode; isActive?: boolean; }) => { return ( <a href={href} className={cn( "inline-block rounded-lg px-2 py-1 text-sm text-slate-700 hover:bg-slate-100 hover:text-slate-900", )} > {children} </a> ); }; export default PcNavLink;
1.8 Create Mobile Navigation Link component
Create a new file components/layouts/common/TopBar/MobileNavLink.tsx
jsximport Link from "next/link"; import { PopoverButton } from "@headlessui/react"; const MobileNavLink = ({ href, children }: { href: string; children: React.ReactNode }) => { return ( <PopoverButton as={Link} href={href} className="block w-full p-2"> {children} </PopoverButton> ); }; export default MobileNavLink;
2. Usages
Now you can use the TopBar component in any Layout components. For example, we have the DefaultLayout component (with TopBar, Main body and Footer).
jsximport React, { ReactNode } from "react"; import Footer from "./common/Footer"; import TopNavigation from "./common/TopNavigatoin/"; const DefaultLayout = ({ children }: { children: ReactNode }) => { return ( <div className="flex min-h-screen flex-col"> <TopNavigation /> <main className="flex-1">{children}</main> <Footer /> </div> ); }; export default DefaultLayout;
The UI like that, when user is logged in, the Avatar was shown

Just set the session=null in components/layouts/common/TopBar/index.tsx file
jsxconst TopNavigation = () => { // TODO: You can add the function to get user session (or check user signin or not) // const session = { // user: { // firstName: "Bien", // lastName: "Anh", // email: "bientuanh46@gmail.com", // signUpBy: "credentials", // }, // }; const session = null; ... }
The TopBar will show the signin button and signup button

You can handle check user login or not by your self.
Now, you can refer more my DefaultLayout component which uses the TopBar component and Footer component to build the Layout for all pages.