MKT UI
Sections

Site header

Responsive header with primary navigation and a mobile drawer.

Open preview (opens in a new tab)

Installation

npx shadcn@latest add http://localhost:3000/r/site-header.json

MKT UI is not published yet, so this points at your local development server. Set NEXT_PUBLIC_REGISTRY_URL to the deployed origin to show the public command.

Also installs: button, sheet, container, phone-link.

Usage

import { Button } from "@/components/ui/button";
import { SiteHeader } from "@/components/site-header";

<SiteHeader
  logo="Northgate Plumbing"
  logoHref="/"
  navigation={[
    { label: "Services", href: "/services", current: true },
    { label: "Service areas", href: "/areas" },
    { label: "Reviews", href: "/reviews" },
    { label: "FAQ", href: "/faq" },
  ]}
  phone={{ number: "(512) 555-0142", label: "Call" }}
  action={<Button asChild><a href="/quote">Request a quote</a></Button>}
/>

Props

PropTypeDefaultDescription
logo (required)ReactNodeBusiness name or logo element. A text wordmark is a fine default.
logoHrefstring"/"Where the logo links.
navigationHeaderNavItem[][]Primary links. Keep to about five — more and nothing stands out.
actionReactNodePrimary CTA. Shown on desktop and at the bottom of the mobile drawer.
phone{ number, dial?, label? }Tap-to-call number. Local businesses should set this.
stickybooleantrueStick to the top of the viewport on scroll.
menuLabelstring"Open menu"Accessible name for the mobile menu button.

HeaderNavItem

PropTypeDefaultDescription
label (required)stringLink text.
href (required)stringDestination.
currentbooleanMarks the current page. Sets `aria-current="page"`.

Behavior

Height is fixed at 4rem and matches the --mkt-header-height token that scroll-padding-top uses. That is what stops an in-page anchor link from landing with its heading hidden underneath the sticky header. Change the height and update the token:

:root { --mkt-header-height: 5rem; }

The mobile menu is a shadcn Sheet. Escape to close, focus trapped while open, and focus returned to the trigger button on close — all of which is why it is a Sheet rather than a hand-rolled useState panel. Tapping a link closes the drawer.

Navigation collapses below lg (1024px), not md. Four or five marketing links plus a phone number and a CTA genuinely do not fit at tablet width.

Client component

This section carries "use client" for the drawer state. You can still place it directly in a server component — the boundary is inside the section.

Limitations

  • Single-level navigation only. Dropdowns and mega menus (nav-dropdown, nav-mega-menu) are not implemented yet.
  • No announcement bar, breadcrumbs, or mobile action bar yet.
  • Uses plain <a> elements, so a Next.js app does not get client-side navigation from the header. Swapping in next/link is a one-line edit in your installed copy — the section stays framework-neutral so it also works in Vite and Astro.
  • No transparent-over-hero variant yet.

On this page