Skip to content

Conversation

@twjeffery
Copy link
Collaborator

@twjeffery twjeffery commented Nov 17, 2025

Summary

Implements V2 app-header component with responsive navigation and utilities (#3152).

Features Implemented

V2 Structure

  • Named slots: banner, navigation, utilities, phase
  • Version prop with "1" | "2" validation
  • Subline prop for secondary text
  • V2 logo integration (118x32 desktop, 32x32 mobile)

Responsive Features

  • Navigation overflow: Automatic "More" menu when items don't fit
  • Utilities collapse: Mobile menu button when 2+ utility items
  • Logo switching: Desktop/mobile logo variants
  • Service name alignment: Centered on desktop, left-aligned on mobile

AppHeaderMenu Updates

  • Context-aware rendering (navigation slot vs utilities slot)
  • V2 navigation styling when in navigation slot
  • Memory leak prevention (MutationObserver cleanup)

Technical Implementation

  • .v2 scoping pattern for all V2-specific styles
  • 100% V1 backward compatibility preserved
  • Proper cleanup in onDestroy to prevent memory leaks
  • Responsive calculations with debouncing

Related

Testing

Playground page: https://github.com/twjeffery/goa-v2-component-playground/blob/main/src/pages/HeaderPage.svelte

V2

image image image image

V1

image image image

@twjeffery twjeffery linked an issue Nov 17, 2025 that may be closed by this pull request
@twjeffery twjeffery marked this pull request as ready for review November 17, 2025 16:28
@twjeffery twjeffery requested a review from bdfranck November 17, 2025 16:42
@twjeffery twjeffery changed the base branch from v2-2998-coded-component-updates to dev November 18, 2025 02:21
Copy link
Collaborator

@bdfranck bdfranck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested version 1 of the header...

  • ✅ It looks and works like the current header
  • ✅ I don't see any console errors
Image Image Image

Regarding all the new code, @chrisolsen may have some thoughts on the following questions:

  • Should the new utility menu and overflow features stay in the AppHeader or move to new components?
  • Are there any established patterns for communicating between the AppHeader and AppHeaderMenu that Tom could leverage?

The rest looks good to me! 👍 I just have a couple suggestions.

@twjeffery twjeffery force-pushed the v2-header-update branch 2 times, most recently from 0bcd7ed to 0ef4c14 Compare November 21, 2025 06:20
@twjeffery
Copy link
Collaborator Author

twjeffery commented Nov 21, 2025

Thanks for the review @bdfranck

I've updated the PR with the following changes so far:

  • extracted navigation logic into a new component used within the app-header
  • removed console logs
  • added version prop

@twjeffery twjeffery requested a review from bdfranck November 21, 2025 06:21
bdfranck
bdfranck previously approved these changes Dec 5, 2025
Copy link
Collaborator

@bdfranck bdfranck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at the latest changes...

  • ✅ The Menu uses a version property
  • ✅ The Navigation is a separate component
  • ✅ There are no console logs

Looks good to me! 👍

@twjeffery twjeffery requested a review from chrisolsen December 5, 2025 02:38
Comment on lines 81 to 94
if (_slotParentEl) {
// Store observer for cleanup in onDestroy
_observer = new MutationObserver(() => {
checkForCurrentLink();
});
// Observe the slot parent for changes to descendants
_observer.observe(_slotParentEl, {
attributes: true,
attributeFilter: ['class'],
subtree: true
});
}
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already attach a click event to handle when menu items are clicked, although it currently just closes the menu, but it seems that all the logic within this mutation observer could easily be done within that existing event handler.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. Removed the MutationObserver.

Comment on lines 176 to 187
function checkForCurrentLink() {
if (!_slotParentEl) return;
const slotChildren = getSlottedChildren(_slotParentEl);
if (slotChildren.length === 0) return;
const links = slotChildren.filter((el) => el.tagName === "A");
const hasCurrentLink = links.some((link) => link.classList.contains("current"));
_hasCurrentLink = hasCurrentLink;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure why this is necessary. Since it is this component that is performs the setting of the current css class, and when it does it sets a flag indicating that the current link has been set, so we already know if there is a current link.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. Removed this function.

Comment on lines 76 to 88
onDestroy(() => {
// Clean up popover event listeners
if (_popoverEl) {
_popoverEl.removeEventListener("_close", closeMenu);
_popoverEl.removeEventListener("_open", openMenu);
}

// Clean up slot parent event listener
if (_slotParentEl) {
_slotParentEl.removeEventListener("click", closeMenu);
}
});

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't needed, since the all event handlers that are attached internally will be removed when the web component is removed from the dom. Having them doesn't break anything, but it does increase the final build size.

The cases where this should be done, which I am still not 100% sure is needed, is if you are attaching event to a higher up DOM node like the document.body, or something of the like.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Removed the onDestroy block

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.

Header 2.0 Update

4 participants