Let's see what we are going to build .
So let's start with , some basic ui
const navData = [ { name: "Home", href: "/home", }, { name: "About", href: "/about", }, { name: "Projects", href: "/projects", }, { name: "Contact", href: "/contact", }, ]; export default function NavBar() { return ( <div className="flex container w-full mx-auto justify-between items-center font-bold text-2xl px-5 py-6"> <Link href="/"> <h1 className="h-[3.5rem] flex items-center text-center">Logo</h1> </Link> <nav className="hidden md:flex space-x-10 items-center"> {navData.map((n) => { return ( <Link key={n.name} href={n.href}> {n.name} </Link> ); })} </nav> <div className="md:hidden"> <button > <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="white" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16m-7 6h7" /> </svg> </button> </div> </div> ); }
so this is the basic ui to start
Now Let's add Some Functionality for mobile view.
so first we will add some toggle function in it by create a state
const [isModalOpen, setModalOpen] = useState(false);
and connect it to the buttton which is only visible on mobile view ,
<button onClick={() => setModalOpen(!isModalOpen)}> <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="white" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16m-7 6h7" /> </svg> </button>
And i have also updated the ui code, for mobile view.
Updated code
const [isModalOpen, setModalOpen] = useState(false); return ( <div className="flex container w-full mx-auto justify-between items-center font-bold text-2xl px-5 py-6"> <Link href="/"> <h1 className="h-[3.5rem] flex items-center text-center">Logo</h1> </Link> <nav className="hidden md:flex space-x-10 items-center"> {navData.map((n) => { return ( <Link key={n.name} href={n.href}> {n.name} </Link> ); })} </nav> <div className="md:hidden"> {isModalOpen ? ( <div className="bg-[#161B21] border-[1px] border-red-100/20 fixed w-[24rem] right-0 top-0 h-[100vh] transition translate-x-[-1px] rounded-lg text-white" > <div className="pt-5 pb-6 px-5"> <button onClick={() => setModalOpen(!isModalOpen)} className="-mr-2 float-right mb-3" > <svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" aria-hidden="true" className="h-6 w-6" viewBox="0 0 24 24" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" ></path> </svg> </button> <div className="mt-[5rem] z-10 relative"> <nav className="grid gap-y-8"> {navData.map((item) => ( <a key={item.name} href={item.href} className="-m-3 p-3 flex items-center rounded-md hover:bg-black/20 border-[1px] border-gray-500/60" > <h1 className="my-3 ml-3 text-3xl font-bold "> {item.name} </h1> </a> ))} </nav> </div> </div> </div> ) : ( <button onClick={() => setModalOpen(!isModalOpen)}> <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="white" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16m-7 6h7" /> </svg> </button> )} </div> </div> );
And till now you can say we have completed a basic Responsive NavBar. And you can use it in your next big project , but there is one more addition feature for better UX, which is closing the navbar when someone click outside the navbar . Let's add that functionality also.
I am using a custom hook called useOnClickOutside , and my final code look like this
export default function NavBar() { const [isModalOpen, setModalOpen] = useState(false); const ref = useRef<HTMLDivElement>(null); useOnClickOutside(ref, () => setModalOpen(false)); return ( <div className="flex container w-full mx-auto justify-between items-center font-bold text-2xl px-5 py-6"> <Link href="/"> <h1 className="h-[3.5rem] flex items-center text-center">Logo</h1> </Link> <nav className="hidden md:flex space-x-10 items-center"> {navData.map((n) => { return ( <Link key={n.name} href={n.href}> {n.name} </Link> ); })} </nav> <div className="md:hidden"> {isModalOpen ? ( <div ref={ref} className="bg-[#161B21] border-[1px] border-red-100/20 fixed w-[24rem] right-0 top-0 h-[100vh] transition translate-x-[-1px] rounded-lg text-white" > <div className="pt-5 pb-6 px-5"> <button onClick={() => setModalOpen(!isModalOpen)} className="-mr-2 float-right mb-3" > <svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" aria-hidden="true" className="h-6 w-6" viewBox="0 0 24 24" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" ></path> </svg> </button> <div className="mt-[5rem] z-10 relative"> <nav className="grid gap-y-8"> {navData.map((item) => ( <a key={item.name} href={item.href} className="-m-3 p-3 flex items-center rounded-md hover:bg-black/20 border-[1px] border-gray-500/60" > <h1 className="my-3 ml-3 text-3xl font-bold "> {item.name} </h1> </a> ))} </nav> </div> </div> </div> ) : ( <button onClick={() => setModalOpen(!isModalOpen)}> <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="white" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16m-7 6h7" /> </svg> </button> )} </div> </div> ); }
Final ui
Source Code : Github
Top comments (0)