Hubbi & AI

Deep dive: Menus

What this covers

There are two ways the toolkit builds your site's menus: native (hand-coded into your pages) and CMS dynamic (placeholders the portal fills in). This explains what each means, the trade-offs, and how to choose. It doubles as a reference an AI agent can act on.

New in v1.3.0. The toolkit no longer defaults to the CMS menu. It now asks which you want, with no default, before it builds the first page that needs a menu. Before v1.3.0 it defaulted to the CMS all-in-one nav and treated a hand-coded menu as something to avoid; now native menus are a first-class, supported option.

The choice, and how it is made

Before building the first page that needs a menu, Claude asks which menu style you want and explains the trade-offs. Your answer is logged to build-assets/0-the-brand/notes/decisions.md and reused for the whole site, both the primary nav and the footer, so you are not asked again per page.

Native (your own) menus

A native menu is real HTML written into every page: a hand-coded <nav> with a list of links, plus a matching footer <ul>. For example:

<nav class="site-nav">
  <ul class="nav-list">
    <li><a href="../pricing">Pricing</a></li>
    <li><a href="../articles">Articles</a></li>
    <li><a href="../safety">Safety</a></li>
  </ul>
</nav>

Every link is relative, has no .html extension and no trailing slash (Home is the one exception), and points to a page that exists. On first use, the toolkit adds a reusable mobile drawer (its CSS and a little JS) so the native nav is responsive. The footer is the same idea: a hand-coded <ul> of links in place of the footer menu placeholder.

The site audit knows your choice, so it will not flag a native nav; it does check that every link resolves.

CMS dynamic menus

A dynamic menu is a placeholder the portal fills in at render time. There are three:

One quirk with the all-in-one nav. Its styles load after global.css, so trying to override its CSS variables at the same specificity silently does nothing. Style the specific element (for example the drawer) rather than re-declaring the variable.

Native vs dynamic, side by side

Native (hand-coded)CMS dynamic (placeholder)
EditingEdit and re-upload every pageChange once in the portal, no rebuild
Local previewRenders as writtenShows the placeholder token, not the menu
Responsive chromeThe reusable drawer the toolkit addsBuilt in (for the all-in-one nav)
ClarityWhat you see is what you getThe placeholder can confuse some users

How to choose

The same either way

Your Join and Login buttons always use {{join.url}} and {{login.url}}, and your footer legal links always use the {{footerLinks.*Url}} placeholders, whichever menu style you choose. Those are not affected by the menu decision.

How Claude handles it

Claude asks you early with the pros and cons, records your choice in notes/decisions.md, and reuses it for every page and future session, so your nav and footer stay consistent.

Example. "I want to manage my menus in the portal." Claude would use CMS dynamic menus: {{menu.navigation.default}} for the primary nav and {{menu.footer}} for the footer, and note the choice so every new page matches.