Imported from drupal-canvas/headless-templates (
astro/.agents/skills/canvas-navigation-components/SKILL.md). Install upstream withnpx skills add drupal-canvas/headless-templates --skill canvas-navigation-components. Copyright stays with the author.
Canvas navigation components
Project type
Before applying this skill, check package.json for a dependency named
@drupal-canvas/headless or starting with @drupal-canvas/headless-. If one is
present, this is a Canvas Headless codebase — read
canvas-headless first. The decomposition,
naming, and accessibility guidance below applies unchanged, but the fetch
patterns (SWR, JsonApiClient, sortMenu, getPageData from drupal-canvas)
are for Canvas-rendered React projects only; in headless projects fetch menus
with the SDK's JSON:API client (getClient()) instead. If no such dependency is
present, this is a Canvas-rendered React codebase: components are React
(index.jsx/.tsx) and everything in this skill applies as written. These are
the only two project types.
Build navigation that fits Canvas: reusable names, clear props
(variant, menuName) and slots (logo, utilities, mega-menu regions),
correct data source (Drupal menu vs breadcrumb context vs static), and
accessible markup.
This skill stacks on:
canvas-design-decomposition— regions, tree, prop/slot sketch, reuse-first naming before code.canvas-data-fetching— SWR,JsonApiClient, menu resource pattern, Workbench rules.
Then apply canvas-component-metadata,
canvas-component-definition
(including
references/naming.md),
canvas-styling-conventions, and
canvas-component-composability
for slots and repeatable groups.
Workflow (order matters)
1. Decompose (mandatory)
Follow canvas-design-decomposition
through at least Phase E (props/slots) before writing React or
component.yml.
Navigation-specific prompts:
- Separate chrome (bar, drawer shell) from link lists and optional columns (footer, mega-menu). Prefer composition over one god-component.
- Repeating link groups or cards → parent + child pattern per
canvas-component-composability/references/repeatable-content.md. - Use generic
machineNames (main-navigation,footer-navigation), not page-specific names. Express placement in the page, not the component name. - Sketch
variantfor layout modes (horizontal, drawer, compact footer). - Add
menuNamein the sketch when the nav reads from a Drupal menu (see step 2). Use slots for logo, utility links, or CTAs when authors compose those blocks.
2. Choose a data source
See references/data-sources.md for a decision table. Summary:
| Source | When |
|---|---|
| Drupal menu | Editors manage links in Structure → Menus; use menu_items + getResource |
| Breadcrumb | Trail from current page context via getPageData() |
| Static | Rare; document why; still provide sensible defaults or slots |
3. Implement the fetch (Drupal menu)
Use the Navigation / Menu Components section in
canvas-data-fetching:
useSWR(menuName ? ['menu_items', menuName] : null, ([type, id]) => client.getResource(type, id))Array.from(sortMenu(data))when data is valid; otherwiseFALLBACK_LINKS- Always define
FALLBACK_LINKSso Workbench and sites without the menu still render. - Expose
menuNameincomponent.ymlwhen editors should pick the Drupal menu (machine name, e.g.main,footer). Hard-coding only the default in JSX without a prop is fine for examples; production nav that must switch menus should registermenuNameper data-fetching rules. menuNameomitted or null in props: use SWR keynulland show fallback when you need static-only preview behavior.
Do not fabricate JSON:API menu payloads in Workbench mocks. Prefer real loading/error/empty behavior; fallback links cover the empty-menu case.
Menus in Drupal (preferred): Production navigation should live in Drupal
menus (CMS), not only as hardcoded arrays in code. FALLBACK_LINKS are
for Workbench / empty-menu cases — not a long-term substitute for CMS menus on a
real site.
On Acquia Source, prefer creating or updating menus via Source MCP using
acquia-source-navigation-menus
when automating that environment; otherwise use Structure → Menus in Drupal.
Align menu_name with this component’s menuName prop.
For non–Acquia Source targets, use the Drupal admin (or your deployment
process) — do not apply the Source MCP menu skill. If there is no admin/MCP
access, tell the user exactly which menus to create (match menuName /
machine names such as main, footer) and link to Structure → Menus as in
canvas-data-fetching.
4. Breadcrumbs
Breadcrumbs come from page context, not menu_items. Precedent:
examples/components/breadcrumb/index.jsx
(getPageData(), breadcrumbs). Probe or read existing patterns before
inventing fields.
5. Accessibility (minimum)
- Wrap primary link lists in
<nav>with distinctaria-label(oraria-labelledbypointing at visible heading text). - Mobile toggles:
aria-expanded,aria-controlswhen you wire IDs; buttontype="button". - Do not mark every link
aria-current="page"—only the true current item when the design requires it. - Nested lists (mega-menu, footer columns): preserve list semantics where appropriate; keep tab order predictable.
6. Metadata and styling
- Props/slots YAML:
canvas-component-metadata. - Folder and mocks:
canvas-component-definition. - Tailwind tokens:
canvas-styling-conventions.
Reference example
Menu + SWR + sortMenu pattern:
examples/components/main_navigation/index.jsx.
Consider adding menuName to component.yml when editors must choose the
menu without code changes.
Mega-menu and nested menus
- Model composition: parent nav shell + slots for columns or featured blocks; child components for link groups.
- Nested menu shape: do not assume raw JSON:API nesting. Probe deserialized
output with the same
JsonApiClientcall the component will use (seecanvas-data-fetching) before mapping children.
Further reading
Anti-duplication
- Full menu code samples and
menuNameYAML live under Navigation / Menu Components incanvas-data-fetching. - Decomposition phases A–G are not repeated here—use
canvas-design-decomposition.