Navbar with Centered Links, CTA Button and Mobile Menu

A rounded, floating site header with three zones: the logo on the left, four page links centred exactly in the middle, and a sign-in link with a call-to-action button on the right. The current page is marked with a tinted pill. Below 768 pixels the links and buttons collapse behind a menu button, which opens a panel inside the same card with large tap rows and both actions side by side.

Code

import { useState } from "react";

const links = [
  { label: "Product", href: "#", current: true },
  { label: "Pricing", href: "#" },
  { label: "Customers", href: "#" },
  { label: "Guides", href: "#" },
];

export default function NavbarWithCenteredLinksAndMobileMenu() {
  // Starts open so the phone preview shows the menu. Set to false on a real site.
  const [open, setOpen] = useState(true);
  const focus = "focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-700 focus-visible:ring-offset-2";

  return (
    <div className="bg-emerald-50 px-4 py-6 sm:px-6 sm:py-10">
      <header className="mx-auto max-w-5xl rounded-[28px] border border-emerald-950/10 bg-white shadow-sm shadow-emerald-950/5">
        <div className="grid h-16 grid-cols-[1fr_auto] items-center pl-5 pr-3 md:grid-cols-[1fr_auto_1fr]">
          <a href="#" className={`flex w-fit items-center gap-2.5 rounded-full ${focus}`}>
            <svg viewBox="0 0 28 28" aria-hidden="true" className="h-7 w-7">
              <rect width="28" height="28" rx="9" className="fill-emerald-700" />
              <path d="M8 18.5V11l6 5 6-5v7.5" fill="none" stroke="white" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
            <span className="text-base font-semibold tracking-tight text-slate-900">Marlowe Books</span>
          </a>

          <nav aria-label="Main" className="hidden md:block">
            <ul className="flex items-center gap-1">
              {links.map((l) => (
                <li key={l.label}>
                  <a
                    href={l.href}
                    aria-current={l.current ? "page" : undefined}
                    className={`inline-flex h-10 items-center rounded-full px-4 text-sm font-medium transition ${focus} ${l.current ? "bg-emerald-50 text-emerald-800" : "text-slate-600 hover:bg-slate-50 hover:text-slate-900"}`}
                  >
                    {l.label}
                  </a>
                </li>
              ))}
            </ul>
          </nav>

          <div className="flex items-center justify-end gap-1">
            <a href="#" className={`hidden h-10 items-center rounded-full px-4 text-sm font-medium text-slate-600 transition hover:text-slate-900 md:inline-flex ${focus}`}>
              Sign in
            </a>
            <a href="#" className={`hidden h-10 items-center gap-1.5 rounded-full bg-emerald-700 pl-4 pr-3 text-sm font-semibold text-white transition hover:bg-emerald-800 md:inline-flex ${focus}`}>
              Start free trial
              <svg viewBox="0 0 20 20" fill="none" aria-hidden="true" className="h-4 w-4">
                <path d="M7.5 5.5 12 10l-4.5 4.5" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
            </a>
            <button
              type="button"
              aria-expanded={open}
              aria-controls="marlowe-mobile-menu"
              aria-label={open ? "Close menu" : "Open menu"}
              onClick={() => setOpen(!open)}
              className={`inline-flex h-10 w-10 items-center justify-center rounded-full text-slate-700 transition hover:bg-slate-100 md:hidden ${focus}`}
            >
              <svg viewBox="0 0 24 24" fill="none" aria-hidden="true" className="h-5 w-5">
                {open ? (
                  <path d="M6 6l12 12M18 6 6 18" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
                ) : (
                  <path d="M4 8h16M4 16h16" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
                )}
              </svg>
            </button>
          </div>
        </div>

        {open && (
          <div id="marlowe-mobile-menu" className="border-t border-slate-100 px-3 pb-3 pt-2 md:hidden">
            <nav aria-label="Mobile">
              <ul>
                {links.map((l) => (
                  <li key={l.label}>
                    <a
                      href={l.href}
                      aria-current={l.current ? "page" : undefined}
                      className={`flex h-12 items-center justify-between rounded-2xl px-3 text-base font-medium ${focus} ${l.current ? "bg-emerald-50 text-emerald-800" : "text-slate-700 hover:bg-slate-50"}`}
                    >
                      {l.label}
                      {l.current && <span aria-hidden="true" className="h-1.5 w-1.5 rounded-full bg-emerald-700" />}
                    </a>
                  </li>
                ))}
              </ul>
            </nav>
            <div className="mt-3 grid grid-cols-2 gap-2 border-t border-slate-100 pt-3">
              <a href="#" className={`inline-flex h-11 items-center justify-center rounded-full border border-slate-300 text-sm font-semibold text-slate-900 hover:bg-slate-50 ${focus}`}>
                Sign in
              </a>
              <a href="#" className={`inline-flex h-11 items-center justify-center rounded-full bg-emerald-700 text-sm font-semibold text-white hover:bg-emerald-800 ${focus}`}>
                Start free trial
              </a>
            </div>
          </div>
        )}
      </header>
    </div>
  );
}

Install with one command: npx shadcn@latest add https://we.inc/r/navbar-with-centered-links-and-mobile-menu.json

When to use it

How to customize it

Accessibility

Questions

How do I centre navbar links in Tailwind?

Use a three-column grid with `grid-cols-[1fr_auto_1fr]`. The two outer columns take equal space, so the middle column sits in the true centre of the bar even when the logo and the buttons have different widths. Flexbox with `justify-between` only centres the links when both sides are the same width.

How does the mobile menu open and close?

A single `useState` value holds whether the menu is open. The button flips it, and the panel is rendered only when it is true. The panel has `md:hidden`, so it never shows on wider screens whatever the state is.

How do I make the navbar stick to the top of the page?

Add `sticky top-0 z-40` to the outer `<div>`. If you keep the floating card look, leave the outer padding in place so the card does not touch the edge of the window while scrolling.

Can I add a dropdown to one of the links?

Yes. Replace that link with a button that toggles a second piece of state and position a panel under it with `absolute top-full`. The dark navbar with a dropdown in this collection shows the full pattern.

Does it work without React?

The layout and styles work as plain HTML. The menu button needs a few lines of JavaScript to add and remove the `hidden` class on the panel and to update `aria-expanded`.

Related: Dark Navbar with Dropdown Menu and Search Field, Store Navbar with Announcement Bar and Category Row, Split Hero with Email Capture, Button Set: Primary, Secondary, Ghost, Icon and Loading.

More navbars or all free UI components. Start for free to have a full site built around it.

More in Navbars

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap