ADR 0004: Pagina-sidebar-navigatie in het hamburgermenu op kleine schermen

  • Status: geaccepteerd
  • Datum: 2026-07-23
  • Beslissers: Thomas van Minnen

Context

Verschillende user-side pagina’s tonen een linker sidebar-menu: nieuwsfeed, agenda, dashboard, smoelenboek, instellingen en admin. Ze gebruiken allemaal hetzelfde gedeelde SidebarMenuComponent (<sidebar [items]="...">), aangehangen via een named sidebar router-outlet in TwoColumnComponent / ThreeColumnComponent.

Die sidebar-kolom valt op kleine schermen weg (hidden lg:block) zonder mobiele fallback. Gevolg: op mobiel kun je de sub-pagina’s van die menu’s niet meer bereiken. We willen dit generiek oplossen, zodat elke pagina met een sidebar automatisch meedoet.

Beslissing

We maken de pagina-sidebar op kleine schermen bereikbaar in het bestaande hamburgermenu, via een kleine registry. Zo werkt het:

  1. SidebarNavRegistryService (root singleton) houdt de items van de nu-actieve pagina-sidebar bij als signal (plus een optionele navLink). Een owner-guard zorgt dat een pagina die afmeldt de items van een ander niet wist.

  2. Het gedeelde SidebarMenuComponent registreert zichzelf. In ngOnChanges schrijft het zijn items in de registry, in ngOnDestroy maakt het ze weer leeg. Omdat álle sidebar-pagina’s dit ene component gebruiken, doet elke pagina automatisch mee, zonder per-feature code. Drie inputs sturen het gedrag:
    • registerAsPageNav (standaard true) — opt-out zodat een <sidebar> die niet de pagina-navigatie is (o.a. de kopie in het hamburgermenu zelf) zich niet registreert en er geen terugkoppeling ontstaat.
    • navGroupLink — expliciete nav-link om onder te nesten, nodig als die niet gelijk is aan de echte URL (bv. /feed redirect naar /home).
    • onPrimary — donkere kleurvariant voor gebruik op de primary-achtergrond van het hamburgermenu.
  3. Het hamburgermenu (SidenavComponent) toont de geregistreerde items op kleine schermen (lg:hidden, spiegelt de hidden lg:block van de sidebar-kolom), genest onder het bijbehorende nav-item. Het doel-nav-item wordt bepaald via targetNavItemId: een expliciete navGroupLink als die er is, anders het nav-item waarvan de link de langste prefix van de huidige URL is. Voor de rendering hergebruikt het <sidebar [onPrimary]="true" [registerAsPageNav]="false">, zodat iconen, gekleurde bolletjes, dividers en active-staat exact als op de pagina renderen.

  4. Geen dubbeling: items die al als dropdown (een module met eigen children) in het hamburgermenu staan, worden overgeslagen.

Bewust gehouden los van het module-/HeaderService-systeem: dat rendert children ook als chevron in de desktop-header, en dat willen we hier niet — de sidebar-items horen alleen in de hamburger op kleine schermen.

Gevolgen

  • Positief: één generieke haak; nieuwe sidebar-pagina’s krijgen de mobiele fallback gratis, zonder per-feature code (op één regel navGroupLink na waar een redirect speelt). Geen desktop-chevron. Rendering hergebruikt het bestaande component, dus consistent met de pagina.
  • Negatief: het gedeelde SidebarMenuComponent heeft nu een neveneffect (self-registratie) en drie extra inputs. navGroupLink en registerAsPageNav zijn kleine leaks in een verder generieke oplossing.
  • Risico’s: het doel-nav-item wordt heuristisch bepaald (URL-prefix / expliciete link); bij ongebruikelijke routes/redirects kan de nesting misgrijpen. Pagina’s die niet het gedeelde <sidebar> gebruiken (bv. locaties, met een eigen sidebar) vallen buiten deze haak.

Alternatieven

  • Pagina-items als module-children modelleren (zoals de nieuwsfeed via de /feed-module). Afgewezen: dat rendert de children óók als chevron-dropdown in de desktop-header, wat hier niet gewenst is; bovendien zijn dashboard/agenda geen module-children maar hardcoded/service-gedreven.

  • Uitklap-menu boven de content in de gedeelde layout. Afgewezen na afweging: houdt de sub-nav wel in context bij de pagina, maar de wens was expliciet plaatsing in het bestaande hamburgermenu, genest onder het pagina-item.