@shopkit/navigation
v1.5.0
Published
Navigation menu fetching, types, and context for storefront apps
Readme
@shopkit/navigation
Navigation menu data layer for storefront apps — fetches a merchant's menus (incl. multi-column mega menus) from the backend, validates + caches them, and exposes them to widgets via React Context.
Data + logic only — ships no UI. Each storefront designs its own header/footer and renders the menu however it likes. Think weather API, not weather widget.
Two entry points
// server (layout / Server Components) — fetch only
import { getNavMenus, getNavMenu } from "@shopkit/navigation";
// client (widgets) — provider + hook + helpers
import {
NavigationProvider,
useMenu,
getRenderStrategy,
getEffectiveUrl,
hasImage,
getMegaMenuColumns,
isBrokenLink,
getAriaLabel,
} from "@shopkit/navigation/client";The server barrel uses server-only and must never be imported in a Client Component.
Usage
// 1. Root layout (server): fetch the menus, provide them.
const menus = await getNavMenus(); // fetches "main-menu" + "footer" (defaults)
<NavigationProvider menus={menus}>{children}</NavigationProvider>
// 2. A widget (client): read + render via helpers.
const menu = useMenu("main-menu");
(menu?.items ?? []).map((item) => {
if (isBrokenLink(item)) return null;
switch (getRenderStrategy(item)) {
case "mega-menu": /* getMegaMenuColumns(item) → columns; hasImage(leaf) → card */ break;
case "dropdown": /* item.items */ break;
case "external": /* <a target="_blank" href={getEffectiveUrl(item)}> */ break;
case "link": /* <Link href={getEffectiveUrl(item) ?? "/"}> */ break;
}
});Env
| Var | Purpose |
|---|---|
| NEXT_PUBLIC_NAV_MENU_API_URL | Gateway base incl. /api/v1; the package appends /storefront/nav-menus/{handle} |
| NEXT_PUBLIC_MERCHANT_ID | Sent as the gk-merchant-id header |
If unset, fetches return null and widgets degrade gracefully (no crash).
Notes
getNavMenus()always fetches the backend's default/protected menus (main-menu,footer); pass extra handles for additional custom menus.- The API omits inapplicable keys (no
urlon mega nodes;external_urlonly at depth 0) — the schema handles this; render via the helpers, not raw fields. - Decide a leaf is a card vs. a text link with
hasImage(item), neverresource_type.
Full guide: plans/mega-menu/FLOW.md (Widget Author Contract in §4.1).
