Class AppNavLayout

java.lang.Object
com.vaadin.flow.component.Component
com.vaadin.flow.component.applayout.AppLayout
org.vaadin.addons.joelpop.appnavlayout.ui.layout.appnav.AppNavLayout
All Implemented Interfaces:
com.vaadin.flow.component.AttachNotifier, com.vaadin.flow.component.DetachNotifier, com.vaadin.flow.component.HasElement, com.vaadin.flow.component.HasStyle, com.vaadin.flow.router.AfterNavigationObserver, com.vaadin.flow.router.internal.AfterNavigationHandler, com.vaadin.flow.router.RouterLayout, Serializable

@JsModule("./app-nav-layout.ts") public abstract class AppNavLayout extends com.vaadin.flow.component.applayout.AppLayout implements com.vaadin.flow.router.AfterNavigationObserver
Base application layout providing adaptive navigation: a bottom icon bar with a secondary tab bar on phone, a permanent left-strip rail on tablet, and a drawer-based SideNav on desktop.

Subclass, supply a title via super(...), and annotate with Layout. The DrawerToggle and drawer are wired automatically; the nav-item content for each of the five device/orientation scenarios this layout distinguishes — desktop, tablet portrait, tablet landscape, phone portrait, and phone landscape — is built by an independently pluggable NavRenderer, supplied lazily since only one scenario is ever relevant to a given session. See setDesktopNavRenderer(Supplier), setTabletPortraitNavRenderer(Supplier), setTabletLandscapeNavRenderer(Supplier), setPhonePortraitNavRenderer(Supplier), and setPhoneLandscapeNavRenderer(Supplier) (plus the setTabletNavRenderer(Supplier)/ setPhoneNavRenderer(Supplier) convenience setters covering both orientations at once), defaulting to SideNavDrawerNavRenderer (desktop), SideRailNavRenderer (tablet, both orientations), and TouchBarNavRenderer (phone, both orientations) respectively. The NavType chrome built for a scenario (rail vs. bottom bar vs. drawer) is not a separate choice — it's NavRenderer.navType() of whichever renderer is configured for that scenario, so a scenario's renderer and its chrome can never disagree with each other.

The active scenario is re-evaluated dynamically on touch devices whenever the viewport size changes (rotation, split-screen resize), switching nav components in place without a page reload.

Use the purpose-named methods to place adaptive content:

Override the nav grouping strategy via setNavGrouper(NavGrouper) and the SideNavItem renderer via setNavNodeRenderer(ComponentRenderer). Changes to any nav configuration setter take effect immediately, even after attachment.

Per-view header content is assembled automatically on each navigation. Views implementing HasViewHeaderTitle supply an icon+title component (desktop only). Views implementing HasViewHeaderComponent supply an action component shown on both platforms.

addToNavbar(Component...) is preserved as an escape hatch.

All environment-specific values are supplied by the subclass constructor.

Rail mode is built entirely from standard AppLayout constructs. The rail is AppLayout's own navbar-bottom slot (the same slot the ordinary touch bottom bar uses), repositioned and restyled via CSS keyed on the nav-rail attribute this class sets on itself — not a distinct part of its own. Any companion component that understands AppLayout's standard navbar-top/navbar-bottom contract therefore interoperates with rail mode automatically.

See Also:
  • Nested Class Summary

    Nested classes/interfaces inherited from class com.vaadin.flow.component.applayout.AppLayout

    com.vaadin.flow.component.applayout.AppLayout.AppLayoutI18n, com.vaadin.flow.component.applayout.AppLayout.Section
  • Constructor Summary

    Constructors
    Modifier
    Constructor
    Description
    protected
    Creates an AppNavLayout with the default renderers for each scenario (phone → touch, tablet → rail, desktop → sidenav).
  • Method Summary

    Modifier and Type
    Method
    Description
    protected void
    addBranding(com.vaadin.flow.component.Component... components)
    Adds brand/identity content.
    com.vaadin.flow.shared.Registration
    addNavTypeChangedListener(com.vaadin.flow.component.ComponentEventListener<NavTypeChangedEvent> listener)
    Adds a listener for NavTypeChangedEvent, fired whenever the active NavType is determined and applied — including on first attachment.
    void
    addToNavbar(com.vaadin.flow.component.Component... components)
    Appends components directly to the top bar row.
    void
    afterNavigation(com.vaadin.flow.router.AfterNavigationEvent event)
    On each navigation: assembles the viewHeaderSlot from the current view's HasViewHeaderTitle and HasViewHeaderComponent if present, and re-invokes the active NavRenderer(s) so active-item highlighting and drill-down content stay current.
    protected boolean
    Returns true if this session is using touch or rail nav (not desktop SideNav).
    protected void
    onAttach(com.vaadin.flow.component.AttachEvent attachEvent)
     
    protected void
    Called whenever the active NavType is determined and applied — including on first attachment, not just on later changes.
    protected void
    Overrides the NavRenderer used for the desktop scenario, constructed at most once, the first time it's actually needed.
    protected void
    Overrides the nav grouping strategy.
    protected void
    setNavMatchNested(boolean matchNested)
    Controls whether desktop SideNavItems use nested-route matching (SideNavItem.setMatchNested(boolean)), which causes a parent item to appear active whenever any of its child routes is current.
    protected void
    setNavNodeRenderer(com.vaadin.flow.data.renderer.ComponentRenderer<com.vaadin.flow.component.sidenav.SideNavItem, NavNode> renderer)
    Overrides the SideNavItem renderer for the desktop side nav.
    protected void
    Overrides the predicate used to determine whether the current navigation path belongs to a nav item's section.
    protected void
    Overrides the NavRenderer used for the landscape-phone scenario, constructed at most once, the first time it's actually needed.
    protected void
    Overrides the NavRenderer used for both phone orientations at once, sharing a single memoized instance between them — equivalent to calling setPhonePortraitNavRenderer(Supplier) and setPhoneLandscapeNavRenderer(Supplier) with a shared supplier, not two independent ones.
    protected void
    Overrides the NavRenderer used for the portrait-phone scenario, constructed at most once, the first time it's actually needed.
    protected void
    Overrides the NavRenderer used for the landscape-tablet scenario, constructed at most once, the first time it's actually needed.
    Overrides the physical-screen-shorter-side threshold, in CSS pixels, used to distinguish DeviceType.TABLET from DeviceType.PHONE among touch devices (default 768 — the common responsive-design convention for the tablet/phone boundary, matching an iPad's portrait-mode shortest side and Bootstrap's md breakpoint).
    protected void
    Overrides the NavRenderer used for both tablet orientations at once, sharing a single memoized instance between them — equivalent to calling setTabletPortraitNavRenderer(Supplier) and setTabletLandscapeNavRenderer(Supplier) with a shared supplier, not two independent ones.
    protected void
    Overrides the NavRenderer used for the portrait-tablet scenario, constructed at most once, the first time it's actually needed.
    protected void
    setUserMenu(com.vaadin.flow.component.Component userMenu)
    Sets the user-context widget (avatar, name, account menu).
    protected void
    setViewIconGenerator(Function<com.vaadin.flow.server.menu.MenuEntry, Supplier<com.vaadin.flow.component.icon.Icon>> generator)
    Sets the icon generator for leaf nav items.
    protected void
    setViewNavGroupResolver(Function<com.vaadin.flow.server.menu.MenuEntry, NavGroup> resolver)
    Sets the nav-group resolver used by the default PathPrefixNavGrouper.
    protected void
    setViewTitleGenerator(Function<com.vaadin.flow.server.menu.MenuEntry, String> generator)
    Sets the title generator for leaf nav items in the desktop SideNav.

    Methods inherited from class com.vaadin.flow.component.applayout.AppLayout

    addToDrawer, addToNavbar, getContent, getI18n, getPrimarySection, isDrawerOpened, isOverlay, remove, setContent, setDrawerOpened, setI18n, setPrimarySection, showRouterLayoutContent

    Methods inherited from class com.vaadin.flow.component.Component

    addListener, bindVisible, findAncestor, fireEvent, from, get, getChildren, getElement, getEventBus, getId, getListeners, getLocale, getParent, getTestId, getTranslation, getTranslation, getTranslation, getTranslation, getTranslation, getTranslation, getUI, hasListener, isAttached, isTemplateMapped, isVisible, onDetach, onEnabledStateChanged, removeFromParent, scrollIntoView, scrollIntoView, set, setElement, setId, setTestId, setVisible

    Methods inherited from class Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

    Methods inherited from interface com.vaadin.flow.component.AttachNotifier

    addAttachListener

    Methods inherited from interface com.vaadin.flow.component.DetachNotifier

    addDetachListener

    Methods inherited from interface com.vaadin.flow.component.HasElement

    getElement

    Methods inherited from interface com.vaadin.flow.component.HasStyle

    addClassName, addClassNames, bindClassName, bindClassNames, getClassName, getClassNames, getStyle, hasClassName, removeClassName, removeClassNames, setClassName, setClassName

    Methods inherited from interface com.vaadin.flow.router.RouterLayout

    removeRouterLayoutContent
  • Constructor Details

    • AppNavLayout

      protected AppNavLayout()
      Creates an AppNavLayout with the default renderers for each scenario (phone → touch, tablet → rail, desktop → sidenav).
  • Method Details

    • onAttach

      protected void onAttach(com.vaadin.flow.component.AttachEvent attachEvent)
      Overrides:
      onAttach in class com.vaadin.flow.component.Component
    • addBranding

      protected void addBranding(com.vaadin.flow.component.Component... components)
      Adds brand/identity content. Desktop: placed in the header after the DrawerToggle. Mobile: placed at the top of the navigation drawer. Pass individual components; do not pre-wrap in a layout container.
    • setUserMenu

      protected void setUserMenu(com.vaadin.flow.component.Component userMenu)
      Sets the user-context widget (avatar, name, account menu). Desktop: placed trailing in the header. Mobile: placed at the bottom of the navigation drawer.
    • setNavPathMatcher

      protected void setNavPathMatcher(BiPredicate<String,String> matcher)
      Overrides the predicate used to determine whether the current navigation path belongs to a nav item's section. Used by touch/rail nav to highlight the active icon. Default: String.equals(Object) (exact match).

      Note: this predicate governs touch/rail active-item detection only. Desktop SideNav highlights items via Vaadin's own router matching, which is configured separately via setNavMatchNested(boolean).

    • setNavMatchNested

      protected void setNavMatchNested(boolean matchNested)
      Controls whether desktop SideNavItems use nested-route matching (SideNavItem.setMatchNested(boolean)), which causes a parent item to appear active whenever any of its child routes is current. Default: false (items highlight only on an exact route match).

      Set to true when sub-routes should keep the parent nav item highlighted, for example when using a prefix-based path matcher.

    • setNavGrouper

      protected void setNavGrouper(NavGrouper grouper)
      Overrides the nav grouping strategy. Default: PathPrefixNavGrouper.

      Important: replacing the grouper severs the automatic wiring that the default PathPrefixNavGrouper maintains to setViewNavGroupResolver(Function) and setViewIconGenerator(Function). After this call, those two setters no longer influence grouping or leaf icons — they still update internal fields and trigger a nav repopulation, but the custom grouper is not consulted for those values. Configure the custom grouper directly before passing it here.

    • setNavNodeRenderer

      protected void setNavNodeRenderer(com.vaadin.flow.data.renderer.ComponentRenderer<com.vaadin.flow.component.sidenav.SideNavItem, NavNode> renderer)
      Overrides the SideNavItem renderer for the desktop side nav.
    • setDesktopNavRenderer

      protected void setDesktopNavRenderer(Supplier<NavRenderer> renderer)
      Overrides the NavRenderer used for the desktop scenario, constructed at most once, the first time it's actually needed. Default: SideNavDrawerNavRenderer.

      If this scenario is currently active, it is torn down and rebuilt immediately.

    • setTabletPortraitNavRenderer

      protected void setTabletPortraitNavRenderer(Supplier<NavRenderer> renderer)
      Overrides the NavRenderer used for the portrait-tablet scenario, constructed at most once, the first time it's actually needed. Default: SideRailNavRenderer.

      If this scenario is currently active, it is torn down and rebuilt immediately.

    • setTabletLandscapeNavRenderer

      protected void setTabletLandscapeNavRenderer(Supplier<NavRenderer> renderer)
      Overrides the NavRenderer used for the landscape-tablet scenario, constructed at most once, the first time it's actually needed. Default: the same memoized SideRailNavRenderer instance as the portrait-tablet default (see setTabletNavRenderer(Supplier)) — both resolve to NavType.RAIL by default and need no orientation-specific behavior.

      If this scenario is currently active, it is torn down and rebuilt immediately.

    • setTabletNavRenderer

      protected void setTabletNavRenderer(Supplier<NavRenderer> renderer)
      Overrides the NavRenderer used for both tablet orientations at once, sharing a single memoized instance between them — equivalent to calling setTabletPortraitNavRenderer(Supplier) and setTabletLandscapeNavRenderer(Supplier) with a shared supplier, not two independent ones. Both orientations resolve their chrome from renderer's own navType(), so e.g. supplying SideNavDrawerNavRenderer correctly gives both orientations sidenav chrome — this is the same sharing relationship both tablet orientations and phone's two orientations already have by default (see the field comment above), just with an explicit renderer instead.
    • setPhonePortraitNavRenderer

      protected void setPhonePortraitNavRenderer(Supplier<NavRenderer> renderer)
      Overrides the NavRenderer used for the portrait-phone scenario, constructed at most once, the first time it's actually needed. Default: TouchBarNavRenderer.

      If this scenario is currently active, it is torn down and rebuilt immediately.

    • setPhoneLandscapeNavRenderer

      protected void setPhoneLandscapeNavRenderer(Supplier<NavRenderer> renderer)
      Overrides the NavRenderer used for the landscape-phone scenario, constructed at most once, the first time it's actually needed. Default: the same memoized TouchBarNavRenderer instance as the portrait-phone default (see setPhoneNavRenderer(Supplier)) — both resolve to NavType.TOUCH by default and need no orientation-specific behavior.

      If this scenario is currently active, it is torn down and rebuilt immediately.

    • setPhoneNavRenderer

      protected void setPhoneNavRenderer(Supplier<NavRenderer> renderer)
      Overrides the NavRenderer used for both phone orientations at once, sharing a single memoized instance between them — equivalent to calling setPhonePortraitNavRenderer(Supplier) and setPhoneLandscapeNavRenderer(Supplier) with a shared supplier, not two independent ones. This is the right default relationship for phone specifically, since both orientations already resolve to the same NavType and the same slot; using two independently-constructed instances would leave a stale one still attached after a same-session orientation change re-resolves to the other.
    • setViewNavGroupResolver

      protected void setViewNavGroupResolver(Function<com.vaadin.flow.server.menu.MenuEntry, NavGroup> resolver)
      Sets the nav-group resolver used by the default PathPrefixNavGrouper. Return null to use path-based grouping for an entry.

      Takes effect via the default PathPrefixNavGrouper's lambda closure over this field; has no effect if setNavGrouper(NavGrouper) has been called with a custom grouper.

    • setViewIconGenerator

      protected void setViewIconGenerator(Function<com.vaadin.flow.server.menu.MenuEntry, Supplier<com.vaadin.flow.component.icon.Icon>> generator)
      Sets the icon generator for leaf nav items. Return null or a supplier returning null to show no icon.

      Takes effect via the default PathPrefixNavGrouper's lambda closure over this field; has no effect if setNavGrouper(NavGrouper) has been called with a custom grouper.

    • setViewTitleGenerator

      protected void setViewTitleGenerator(Function<com.vaadin.flow.server.menu.MenuEntry, String> generator)
      Sets the title generator for leaf nav items in the desktop SideNav. Return null to fall back to @Menu#title().

      Note: this generator applies to desktop SideNavItem labels only. Touch and rail nav item labels always use NavNode.title() (derived from @Menu(title=...)); this generator has no effect on those surfaces.

    • afterNavigation

      public void afterNavigation(com.vaadin.flow.router.AfterNavigationEvent event)
      On each navigation: assembles the viewHeaderSlot from the current view's HasViewHeaderTitle and HasViewHeaderComponent if present, and re-invokes the active NavRenderer(s) so active-item highlighting and drill-down content stay current.

      Desktop: title (left) + action component (right) when either is present. Mobile: action component only; title is omitted to conserve vertical space.

      Specified by:
      afterNavigation in interface com.vaadin.flow.router.internal.AfterNavigationHandler
    • onNavTypeChanged

      protected void onNavTypeChanged(NavTypeChangedEvent event)
      Called whenever the active NavType is determined and applied — including on first attachment, not just on later changes. Default is a no-op. Override to react to nav-type changes in a subclass or companion code; for code that doesn't subclass AppNavLayout, see addNavTypeChangedListener(ComponentEventListener).
    • addNavTypeChangedListener

      public com.vaadin.flow.shared.Registration addNavTypeChangedListener(com.vaadin.flow.component.ComponentEventListener<NavTypeChangedEvent> listener)
      Adds a listener for NavTypeChangedEvent, fired whenever the active NavType is determined and applied — including on first attachment. For subclasses, overriding onNavTypeChanged(NavTypeChangedEvent) is usually simpler.
      Returns:
      a registration for removing the listener
    • isMobile

      protected boolean isMobile()
      Returns true if this session is using touch or rail nav (not desktop SideNav).

      Returns false before the first onAttach(AttachEvent) completes, because device detection requires a client round-trip. Do not call this from a subclass constructor.

    • addToNavbar

      public void addToNavbar(com.vaadin.flow.component.Component... components)
      Appends components directly to the top bar row. Prefer the named adaptive methods.
      Overrides:
      addToNavbar in class com.vaadin.flow.component.applayout.AppLayout
    • setTabletMinShortSidePx

      public AppNavLayout setTabletMinShortSidePx(int px)
      Overrides the physical-screen-shorter-side threshold, in CSS pixels, used to distinguish DeviceType.TABLET from DeviceType.PHONE among touch devices (default 768 — the common responsive-design convention for the tablet/phone boundary, matching an iPad's portrait-mode shortest side and Bootstrap's md breakpoint).

      If the layout is already attached, device type is re-evaluated and the nav type re-applied immediately.

      Returns:
      this, for chaining
      Throws:
      IllegalArgumentException - if px is negative