Home
Wiki
Home
Wiki
  1. 2. Components
  • Back to home
  • 1. Themes
  • Vs Code
    • Getting Started
  • Kitchenware
    • Layout
      • New Layout
      • Legacy Layout
    • Components
      • Announcement
      • Banner Carousel
      • Banner With Products Carousel
      • Blog Category List
      • Blog List
      • Brand List
      • Brands Carousel
      • Breadcrumb
      • Call To Action
      • Cart
      • Categories List
      • Change Password
      • Checkout
      • Cookie Manager
      • Filter list
      • Footer
      • Forgot Password
      • Form
      • Hero Carousel
      • Icon Block
      • Invitation
      • Last Visited Products
      • Layout
      • Login
      • Map
      • Nav Bar
      • Offer
      • Product Attachments
      • Product Attributes
      • Product Documentation
      • Product Expected
      • Product Modal
      • Products Block
      • Products Carousel
      • Product Single
      • Profile
      • Quote
      • Register
      • Related Products
      • Search
      • Stores
      • Subscribe Newsletter
      • Text with Image
      • Top Bar
      • Video
    • Reusables
      • Getting Started
    • Assets
      • Getting Started
    • SDK
      • Products
        • _findProductsByCategory
        • _findProductsByIds
        • _findProductsByTitle
        • _findProductsByFilter
        • _findProductsByCriteria
        • _findProductsAndCalculate
        • _findProductsThenCalculate
        • _getProductAttributeSet
        • _setLastVisited
      • Categories
        • _findCategoryTreeById
        • _findCategoriesByIds
        • _findCategoryByAlias
        • _findCategoryTreeByAlias
        • _getCategoryContent
      • Collections
        • _getCollectionContent
        • _findCollectionsByIds
        • _findCollectionsByIdsThenCalculate
      • Brands
        • _getBrandContent
        • _findBrandsByIds
      • Cart
        • _addToCartMulti
        • _addToCart
        • _setCart
        • _clearCart
        • _setCartListener
        • _removeFromCart
        • _calculateCart
      • Checkout
        • _startCheckout
        • _updateCheckout
        • _completeCheckout
      • Shopping Lists
        • _getShoppingLists
        • _updateShoppingList
        • _createShoppingList
        • _deleteShoppingList
        • _getShoppingListByAlias
      • Navigation
        • _getFooterMenu
        • _getHeaderMenu
      • Users
        • _getUserById
      • Utils
        • _calculateCurrency
        • _getCurrencySymbol
        • _getCulture
        • _subscribeToNewsletter
        • _findUnitsByIds
  • Noir
    • 0. Introduction
    • 1. Structure
      • Overview
      • LayoutA.liquid
      • ComponentsList.liquid
      • Metas.liquid
      • CssVariables.liquid
      • Json.liquid
      • GoogleTagManager.liquid
      • StagingButton.liquid
    • 2. Components
      • Overview
      • Announcement
      • BannerCarousel
      • BlogCategoryList
      • BlogList
      • BrandList
      • Breadcrumb
      • Cart
      • CategoriesList
      • ChangePassword
      • Checkout
      • CookieManager
      • FilterList
      • Footer
      • ForgotPassword
      • Form
      • IconBlock
      • Invitation
      • LastVisitedProducts
      • Login
      • Map
      • NavBar
      • ProductAttachments
      • ProductAttributes
      • ProductComparison
      • ProductDocumentation
      • ProductMixList
      • ProductsBlock
      • ProductsCarousel
      • ProductSingle
      • Profile
      • Register
      • RelatedProducts
      • SingleBlog
      • Stores
      • TextWithImage
      • ThankYouPage
      • TopBar
      • Wishlist
    • 3. Reusables
      • Overview
      • Addresses
      • BillingRetail
      • AddressForm
      • AnnouncementModal
      • BackToTop
      • Company
      • General
      • Login
      • LoginModal
      • Orders
      • Payment
      • ProductAttachments
      • ProductAttributes
      • ProductComparisonButton
      • ProductComparisonFloatingButton
      • ProductGridItem
      • ProductListItem
      • ShoppingListsButton
      • ProductModal
      • ProfileInfo
      • PromptModal
      • Register
      • Shipping
      • ShoppingLists
      • ShoppingListsNavbar
      • Toast
      • Users
      • VariantContent
      • WishlistButton
      • Services
    • 4. Assets
      • Fonts
      • Images
      • Templates
      • Javascript
        • Overview
        • theme.js
      • Css / Scss
        • Overview
        • ThemeClasses
    • 5. SDK
      • Overview
      • LiquidGlobals
      • ServicesSDK
  1. 2. Components

NavBar

Purpose#

NavBar renders the storefront header navigation:
Company logo / favicon fallback.
A responsive menu with support for:
Mega menus (Vertical/Horizontal)
Burger menu (desktop overlay + fixed panel)
Simple menu (classic dropdown behavior)
Multi-level navigation (up to 4 nested submenu levels in the template).
Optional search (with live results + optional voice search).
Optional language switcher (mobile UI is implemented in this template; desktop language UI may be elsewhere in the header).
Integrations with global theme behavior (GA “select item” event dispatch for search results).
It’s rendered as a header component (SectionHeader).

Inputs (model contract)#

{
  "unReadAnnouncements": 0,
  "navigations": [
    {
      "navigationTitle": "Sample navigation title",
      "url": "/sample",
      "image": {},
      "banners": [],
      "bannersLink": "",
      "bannersText": "Sample text",
      "menuIcon": {},
      "navigations": [
        {
          "navigationTitle": "Sample navigation title",
          "url": "/sample",
          "image": {
            "id": "Image Id",
            "link": "https://example.com/media/sample.jpg"
          },
          "banners": [
            {
              "image": {
                "id": "Banner image Id",
                "link": "https://example.com/media/sample-banner.jpg"
              }
            },
            "..."
          ],
          "bannersLink": "",
          "bannersText": "Sample text",
          "menuIcon": {},
          "navigations": [
            {
              "navigationTitle": "Sample navigation title",
              "url": "/sample",
              "image": {
                "id": "Image Id",
                "link": "https://example.com/media/sample.jpg"
              },
              "banners": [],
              "bannersLink": "",
              "bannersText": "",
              "menuIcon": {},
              "navigations": [
                {
                  "navigationTitle": "Sample navigation title",
                  "url": "/sample",
                  "image": {
                    "id": "Image Id"
                  },
                  "banners": [],
                  "bannersLink": "",
                  "bannersText": "",
                  "menuIcon": {}
                },
                "..."
              ]
            },
            "..."
          ]
        },
        "..."
      ]
    },
    "..."
  ],
  "name": "NavBar",
  "view": "Default",
  "section": "SectionHeader",
  "settings": {
    "showSearch": true,
    "showLanguage": false,
    "showMenuIcons": false,
    "displayCategoryImages": false,
    "menuType": "Mega",
    "menuOrientation": "Vertical",
    "subMenuLevels": "AllLevels",
    "menuHelperText": "Sample text",
    "id": "Component Id",
    "section": "SectionHeader",
    "type": "NoirNavBar",
    "name": "NavBar",
    "configuredInContentApi": true,
    "view": "Default",
    "displayName": "",
    "cssClass": "",
    "header": "",
    "alignment": "Left"
  },
  "translations": {
    "navbarLogoFor": "Sample text",
    "goToHomepage": "Sample text",
    "openLoginModal": "Sample text",
    "...": "..."
  }
}

Data contract notes (what the template expects)#

model.Settings.Id
Used to render the wrapper id: id="comp-{{ id }}".
model.Settings.menuType
Values observed in template logic: Mega, Burger, Simple (and anything else treated as “not simple” in some branches).
model.Settings.menuOrientation
Used when menuType == 'Mega' to change layout and which submenu types open on click. Values used: Vertical / Horizontal.
model.Settings.subMenuLevels
Used to decide whether deeper levels are available/laid out (values used in template: OneLevel, TwoLevels, AllLevels).
model.navigations[]
Each navigation item can contain nested navigations[] (the template supports deep nesting up to level 4).
Common fields used:
navigationTitle
url
menuIcon.link (used only for Burger menu + when showMenuIcons = true)
image.link (used for category image previews in Mega Horizontal when displayCategoryImages = true)
banners[] (used for Mega Vertical to show promotional banners to the side)
bannersText, bannersLink (note: the template checks these, but the link is referenced as nav.bannerLink in one place—see Notes)
model.unReadAnnouncements
Read at the top of the template; used later in the markup (outside the snippet we reviewed). It’s part of the header UX for announcements/notifications.
Global data dependencies (from GlobalData):
GlobalData.Settings.logo.link, logoLight.link, favicon.link
GlobalData.Settings.noImage.link (fallback) + theme fallback Assets/images/no-image.svg
GlobalData.Company.Name, GlobalData.Company.Languages
GlobalData.CurrentLanguage / GlobalData.Company.DefaultLanguage
GlobalData.Settings.EnableShoppingLists, EnableWishlist

JavaScript#

Default.js defines a global Alpine factory object navbardefault.

navbardefault.initComponent(menuType, menuOrientation)#

Creates the Alpine component state for the navbar/menu system.
State highlights:
isMobile: computed from window.innerWidth < 1440 (updated on resize).
isMenuVisible / isMenuOpen: two-phase open animation control.
isMenuVisible controls whether the element should be present/visible at all.
isMenuOpen controls the slide-in/out class toggles.
Level open/visible tracking + hiddenSiblings:
On mobile it hides sibling menu items when drilling down into submenu levels.

init()#

Measures initial topbarHeight and navbarHeight.
Attaches:
resize listener: updates isMobile, then re-measures heights after 500ms
scroll listener: re-measures heights (keeps sticky/fixed layout calculations correct)
Advice:
If you change header layout (TopBar/NavBar heights) or add additional fixed rows, ensure the selectors used in updateTopbarHeight() / updateNavbarHeight() still match.

searchComponent()#

Returns a nested Alpine object used specifically for the search UI.
It exposes:
searchText, resultProducts, flags like showSearchResult, searchLoading
maxSearchResult = 5
a debounced search() method and navigation helpers.
search()#
Clears current results and clears any pending debounce timer.
If searchText is empty:
hides results and stops loading
Else:
shows results + loading
starts a 400ms debounce timer
calls:
servicesreusabledefault.findProductsByCriteria(criteria)
stores the resulting array into resultProducts (if non-empty)
always sets searchLoading = false in finally
Advice:
This depends on servicesreusabledefault being loaded globally (it’s a reusable service layer).
If you change maxSearchResult, keep pageSize = maxSearchResult + 1 pattern so the UI can infer “there are more results”.
redirectToSearch()#
If searchText.trim() isn’t empty, redirects to:
/search?s=<encoded query>
Advice:
This is hardcoded to /search with query param s. If the Search page changes its query contract, update this.
triggerVoiceSearch()#
Uses Web Speech API (SpeechRecognition or webkitSpeechRecognition).
If not supported, it alert()s an English message.
On result: sets searchText and shows the results panel.
Advice:
Language is hardcoded to en-US. If you want it localized, map it from GlobalData.CurrentLanguage.
Consider replacing alert() with the theme toast store for consistent UX.

sendSelectEvent(product, listName, position)#

Prepares GA items using prepareListProducts([product]).
Calls sendGAEvent("selectItem", { listName, items, position }).
Advice:
This relies on global analytics helpers (prepareListProducts, sendGAEvent).
Make sure the product object shape matches what prepareListProducts expects (typically includes id, name, price, brand, etc.).

Height/measurement helpers#

updateNavbarHeight(): reads .navbar height
updateLanguageHeight(): reads .navbar__menu__wrapper .language-wrapper height
updateTopbarHeight(): reads .topbar height
menuHeight getter: window.innerHeight - topbarHeight
menuPaddingTop getter: returns navbarHeight as a fallback padding-top
Advice:
These functions are central to correct submenu sizing on desktop Mega menus. If you add/remove padding wrappers, re-test desktop submenu heights.

toggleMenu()#

Handles open/close of the entire menu.
Behaviors:
On open:
sets isMenuVisible = true
on mobile:
waits one tick + RAF, then sets isMenuOpen = true
locks body scroll (document.body.style.overflow = "hidden")
measures languageHeight
on desktop, sets isMenuOpen = true immediately
On close:
sets isMenuOpen = false
on mobile: waits for transitionend (menu slide-out), then:
resets submenu states
clears hiddenSiblings
unlocks body scroll
sets isMenuVisible = false
on desktop: just hides (isMenuVisible = false)
Advice:
If you adjust transitions/classes, ensure the element referenced as this.$refs.mobileMenu still has a CSS transition; otherwise transitionend might never fire and the state won’t reset.

childHover(submenuIndex, hovered)#

Stores hover state into submenuHovered[submenuIndex].
(Used by template sections not shown in our snippet; it’s the standard pattern to avoid closing panels while moving the cursor inside complex mega menus.)

getMaxSubmenuHeight(index)#

Finds #submenu{index} then uses its parentNode as the root group.
Collects all .navbar__menu__sub elements.
Clones each element off-screen to measure scrollHeight.
Returns the maximum + 1.
Purpose:
Calculates a consistent submenu height so nested columns don’t “jump” as you go deeper.

getMaxBannersHeight(index)#

Measures #submenu{index} .banners-wrap > div scrollHeight.
Used to keep vertical mega menus aligned with banners.

toggleSubmenuLevel1(index)#

Toggles the first submenu level and resets deeper levels.
On mobile: sets hiddenSiblings[1] to hide other level-1 list items.
On desktop: precomputes submenuHeight and bannersHeight, and recomputes after $nextTick().

toggleSubmenuLevel2(index), toggleSubmenuLevel3(index), toggleSubmenuLevel4(index)#

Each level:
requires the parent level to be open
maintains:
submenuVisibleLevelN (controls display)
submenuOpenLevelN (controls the slide transition state)
on mobile, it waits for transitionend when closing so it can clear submenuVisibleLevelN.
Advice:
The “visible vs open” split is important:
visible keeps the element in the DOM for animation.
open controls translate classes.
If you remove animation classes, simplify by using only one state, otherwise you’ll get stuck panels.

handleResize()#

Resets menu state on resize, and:
sets isMenuVisible based on breakpoint and menu type:
if mobile: false
if desktop and menuType == Burger: false
else: true
unlocks body scroll if switching to desktop.

resetMenu()#

Resets the menu when clicking outside (@click.away="resetMenu" in Liquid).
Very similar to handleResize() but doesn’t recompute isMobile.

navbardefault.handleLogout(logout, modalMessageText, modalButtonCancel)#

Opens a confirmation modal using Alpine.store("modal").open(...).
If user confirms:
clears localStorage:
cartToken, cartData, checkoutToken
redirects to /account/logout
Advice:
This assumes a global modal store exists.
If logout becomes API-driven instead of redirect-driven, implement it here and keep the localStorage cleanup.

Global Alpine stores (used by NavBar)#

From JS + template conventions, NavBar relies on these global items being present in the theme runtime:
Alpine.store("modal")
Used by navbardefault.handleLogout(...) to show a confirmation modal.
servicesreusabledefault
Used by search live results (findProductsByCriteria).
Must exist globally before NavBar JS runs.
GA helpers (global functions)
sendGAEvent(...)
prepareListProducts(...)
Additionally, based on the NavBar translations and common Noir patterns, the header typically also interacts with stores like:
$store.cart (cart popup / cart counter)
$store.toast (errors like AddToCartErrorMessage / UpdateProductQuantityErrorMessage)
$store.loginModal / $store.account (login/register modal)
$store.announcement (announcements modal + unread count)
$store.wishlist, $store.shoppingLists (feature-flagged icons in header)
Those aren’t invoked directly in Default.js, but they’re often used in the rest of Default.liquid (icons / popups / modals) and/or in other header components that appear alongside NavBar.

Dependencies#

Alpine.js (component state + transitions)
Theme service layer: servicesreusabledefault.findProductsByCriteria
Web Speech API (optional voice search)
GA helper functions: sendGAEvent, prepareListProducts
GlobalData: logo, company, languages, feature flags (wishlist/shopping lists)

Notes#

There’s a likely typo in the banners CTA section:
The template checks nav.bannersLink but later uses nav.bannerLink for the <a href="...">.
If a promo banner CTA isn’t working, verify the correct property name and fix the Liquid accordingly.
triggerVoiceSearch() uses alert() and hardcodes recognition.lang = "en-US".
If the storefront language isn’t English, this can feel inconsistent; consider routing the error and messaging through the toast store and mapping language.
Menu breakpoint is hardcoded at 1440px.
If design breakpoints change, update both Liquid responsiveness assumptions and this JS constant.

Extras#

Template behavior (Liquid + Alpine)#

Logo rules#

If GlobalData.Settings.logo.link or logoLight.link exists, the navbar renders <img> logo(s).
If no logo exists, it falls back to showing the company name.
On mobile it prefers favicon.link as a small logo; if missing it falls back to company initials.

Menu rendering#

The root Alpine scope is created via:
NOIR_CODEBLOCK_0
There’s one “menu button” that toggles visibility, and a wrapper that:
behaves differently on mobile vs desktop (isMobile = window.innerWidth < 1440)
changes behavior based on menuType (Burger vs Mega vs Simple)
changes layout based on menuOrientation and subMenuLevels
Submenus:
The template supports (and the JS tracks) open/visible state for:
level 1: submenuOpenLevel1, submenuVisibleLevel2
level 2: submenuOpenLevel2, submenuVisibleLevel3
level 3: submenuOpenLevel3, submenuVisibleLevel4
level 4: submenuOpenLevel4
On mobile, submenus slide horizontally and show a “Back” button per level.
On desktop, submenus are shown/hidden by setting inline display: styles based on open/visible properties.

Search (optional)#

When model.Settings.showSearch is true:
A search button toggles a search panel.
The search panel contains an <input type="search"> bound to searchText.
Typing triggers a debounced API search and shows up to 5 items (+1 extra is fetched so the UI can decide “show all” behavior).

Language switcher (mobile)#

If there are multiple languages (GlobalData.Company.Languages.size > 1):
A mobile-only language listbox is rendered inside the menu wrapper.
It uses a small local Alpine scope: x-data="{ open: false }".
Modified at 2026-04-14 13:18:56
Previous
Map
Next
ProductAttachments
Built with