Skip to content

Align navigation-menu to architecture goals#179

Open
lifeiscontent wants to merge 3 commits into
mainfrom
align/navigation-menu
Open

Align navigation-menu to architecture goals#179
lifeiscontent wants to merge 3 commits into
mainfrom
align/navigation-menu

Conversation

@lifeiscontent

Copy link
Copy Markdown
Collaborator

Closes #136

What the designer specified

From the design system review, these properties are always the same (baked in):

  • Vertical/horizontal stacking of nav items (the trigger chrome uses inline-flex h-8 items-center gap-1)
  • Active item highlight style (data-popup-open:bg-layer-transparent-selected)
  • Item padding (px-3)
  • Icon-to-label gap (gap-1)
  • Focus ring style (focus-visible:ring-2 focus-visible:ring-accent-strong)
  • Transition on state change (built into transition-transform)

These are depends / adjustable (supplied by the caller):

  • Navigation items: label, icon, link/route
  • Active/current item — driven by Base UI's data-popup-open state
  • Nested/grouped items (composed via NavigationMenuContent)
  • Section headers and badge/count indicators

Architecture changes

NavigationMenuIcon node-slot pattern — the previous implementation used flex size-4 items-center justify-center on the container, which forced callers to specify className="size-3.5" on the child SVG (e.g., <ChevronDown aria-hidden className="size-3.5" />). That violates the architecture rule: sized children should be driven by a CSS custom property on the container, not baked onto the child by the caller.

The new implementation aligns with the nodeSlotClass pattern used by AccordionTriggerIcon and other parts:

  • Container: inline-flex shrink-0 items-center justify-center [--node-size:1rem] [&>svg]:size-(--node-size)
  • Child: just <ChevronDown aria-hidden /> — no size class needed

The container's --node-size default (1rem) matches the trigger's line-height context, so the icon reads at the right optical size without any caller-side class.

Both the UI-tier and components-tier stories are updated to drop the now-redundant className="size-3.5" on the ChevronDown icon.

Notes

Needs design approval from @bhaveshraja before merging.

@github-actions

Copy link
Copy Markdown

📚 Storybook preview: https://pr-179-propel-storybook.vamsi-906.workers.dev

Replace the baked `size-4` container on NavigationMenuIcon with the
shared node-slot pattern (`[&>svg]:size-(--node-size)`, defaulting
`--node-size` to 1rem). Callers no longer need to pass `className="size-3.5"`
on the child SVG — the container inherits the token and applies it to
its direct SVG child automatically.

Update both the UI-tier and components-tier stories to drop the now-
redundant size class on the ChevronDown icon.
…tyling

Adds the missing anatomy extensions so every ui part renders a single
element and the components tier only composes parts:

- NavigationMenuTriggerLabel: the trigger's text label beside the Icon
- NavigationMenuContentList: the vertical <ul> stack inside a Content panel
- NavigationMenuLinkTitle / NavigationMenuLinkDescription: the title and
  optional description lines of a rich content link

Link arrangement is now a required variant (an inline item pill vs a
stacked content card) instead of one overloaded shape, so the chrome lives
in one cva. Both stories compose the new parts and register them as
subcomponents; the raw <ul>/<span> classNames that had leaked into the
components-tier story are gone.
The Default story's first product-links list opened as <ul> but closed
as </NavigationMenuContentList>; replace the wrong closing tag with </ul>
in both ui/ and components/ story files.
@lifeiscontent lifeiscontent force-pushed the align/navigation-menu branch from f452643 to f95a41e Compare June 23, 2026 16:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Navigation menu: what should always look the same, and what should be adjustable?

1 participant