Skip to content

Header

Preview



Features

  • Responsive Design: The navigation adapts to various screen sizes such as smartphones, tablets, and PCs.
  • Accessibility: Utilizes skip links and aria-labels for comfortable operation with screen readers.
  • Dark Mode Support: Automatically switches between light and dark modes based on system settings.
  • Intuitive Hamburger Button: Employs a hamburger icon that allows menus to expand and collapse on small screens like smartphones and tablets.
  • Minimal Props: Easily implement rich UI by specifying only logo and navItems.
Tip

Even if the logo text is long, styles are applied to prevent wrapping or overflow.

Properties

Property NameTypeDefault ValueDescription
logostring"LOGO"The string displayed at the top left of the header. Clicking it returns to the root.
navItems{label: string; href: string;}[][ { label: "Home", href: "/" } ]An array of navigation items to display.

Github

Code Example

Header.tsx
import "@/styles/tailwind.css";
import { useState } from "react";
type NavItem = {
label: string;
href: string;
};
type HeaderProps = {
logo?: string;
navItems?: NavItem[];
};
export default function Header({
logo = "LOGO",
navItems = [
{ label: "Home", href: "#" },
{ label: "About", href: "#" },
{ label: "Contact", href: "#" },
],
}: HeaderProps) {
const [isOpen, setIsOpen] = useState(false);
return (
<header className="w-full bg-white text-black dark:bg-black dark:text-white">
<div className="flex items-center justify-between px-4 py-4 md:px-8">
<h1 className="text-xl font-bold overflow-hidden text-ellipsis whitespace-nowrap">
<a
href="/"
className="transition-colors duration-200 hover:opacity-75 focus:opacity-75"
>
{logo}
</a>
</h1>
<button
onClick={() => setIsOpen(!isOpen)}
aria-label="Toggle Menu"
type="button"
aria-expanded={isOpen}
className="inline-flex items-center justify-center p-2 rounded md:hidden hover:bg-gray/10 dark:hover:bg-white/10"
>
<div className="relative w-6 h-6">
<span
className={`absolute block h-[2px] w-6 bg-current transition-transform duration-300 ease-in-out ${
isOpen ? "top-[13px] rotate-45" : "top-[6px]"
}`}
/>
<span
className={`absolute block h-[2px] w-6 bg-current transition-opacity duration-300 ease-in-out ${
isOpen ? "opacity-0" : "top-[13px]"
}`}
/>
<span
className={`absolute block h-[2px] w-6 bg-current transition-transform duration-300 ease-in-out ${
isOpen ? "bottom-[6px] -rotate-45" : "bottom-[6px]"
}`}
/>
</div>
</button>
<nav className="hidden md:flex md:items-center md:space-x-8">
{navItems.map(({ label, href }) => (
<a
key={href}
href={href}
className="block px-2 py-1 transition-opacity duration-200 hover:opacity-75 focus:opacity-75"
>
{label}
</a>
))}
</nav>
</div>
<div
className={`md:hidden transition-[max-height] duration-300 overflow-hidden ${
isOpen
? "max-h-96 border-t border-gray/30 dark:border-white/30"
: "max-h-0"
}`}
>
<ul className="flex flex-col gap-4 py-4 px-4">
{navItems.map(({ label, href }) => (
<li key={href}>
<a
href={href}
className="block px-2 py-1 transition-opacity duration-200 hover:opacity-75 focus:opacity-75"
>
{label}
</a>
</li>
))}
</ul>
</div>
</header>
);
}

Usage

Import the component and incorporate it into your pages or layouts. Override logo and navItems as needed. Adjust the import paths according to each framework, and it’s convenient to manage the above code in separate files.

// import "@/components/Header";
import Header from "@/components/Header";
export default function Layout({ children }) {
return (
<>
<Header
logo="MyWebsite"
navItems={[
{ label: "Home", href: "/" },
{ label: "Services", href: "/services" },
{ label: "Blog", href: "/blog" },
]}
/>
<main id="main">{children}</main>
</>
);
}

Additional Information