Purpose#
LayoutA.liquid is the main layout template of Noir.
It renders the global HTML skeleton and composes the page using:It also loads the theme's CSS/JS and injects runtime globals used by client-side code.
Where it's used#
This layout is the entry point for page rendering in Noir.
All pages that use Layout A will pass through this template.
High-level structure#
Page identity#
The layout relies on a server-provided Root.Page.Identity.* object for page-level decisions:RendersOwnPageTitle — when true, the layout hides its own H1 (the page renders its title itself).
BodyClass — the page-level class added to <body>.
Template — emitted as data-template on <body>.
Handle — emitted as data-handle on <body>.
HTML & language mode#
Sets <html lang="..."> using Root.Page.Metas.IsoLang
Adds the dark class only when both conditions are true:Root.GlobalData.Settings.ShowDarkMode is enabled (settings gate), and
Root.Page.Data.Darkmode is enabled (per-page flag)
Head includes#
In <head>, the layout renders shared infrastructure includes:Structure\CssVariables (rendered with GlobalData.Settings as Settings)
Structure\GoogleTagManager
It also loads core styles:vendor CSS (swiper, lightgallery, nouislider, flatpickr, leaflet, markercluster)
theme CSS bundle: output.css
optional custom CSS: GlobalData.Settings.CustomCss
Preloads the Ubuntu font family (woff2) and the icon font (icons.woff).
Conditionally loads reCAPTCHA Enterprise based on GlobalData.Settings.Captcha (only when at least one captcha action is enabled). The script variant depends on Captcha.GoogleRecaptchaEnterprise.KeyRequiresChallenge.
Asset paths and versioningAsset base path is GlobalData.RootPath
Cache busting uses GlobalData.Settings.Version
Page composition (Header / Body / Footer)#
{% render 'Structure\\ComponentsList' with HeaderComponents as components %}
Main section (#app)#
Inside <main id="app">, Noir renders:A Skip to content accessibility link (targets #app)
Toast reusable: Reusables\Toast\Default
Breadcrumb component: Components\Breadcrumb\Default
Page title block (H1, shown/hidden based on the page flag and breadcrumb depth)
{% render 'Structure\\ComponentsList' with BodyComponents as components %}
Body class#
The layout builds the <body> class list from server-provided values:Root.Page.Identity.BodyClass — page-level class provided by the platform (used for styling/targeting without hardcoding routes).
{{GlobalCssClass}} — platform-provided extra global CSS class.
It also sets data attributes for targeting:data-template="{{ Root.Page.Identity.Template }}"
data-handle="{{ Root.Page.Identity.Handle }}"
handheld-toolbar-enabled — enables layout behavior for the mobile toolbar.
plain-page — added only when the page title block is visible (i.e. when hide_div == false; see H1 visibility rules below).
H1 / page title block#
The layout includes an H1 in a .page-title wrapper:<div class="page-title{% if hide_div %} sr-only{% endif %}" {% if hide_div %} tabindex="-1"{% endif %}>
<div class="container">
<h1 class="-mb-6 lg:-mb-20">{{ Page.metas.title }}</h1>
</div>
</div>
Visibility rules (the hide_div flag):The title block is visually hidden (sr-only) when Root.Page.Identity.RendersOwnPageTitle is true (the page renders its own title, e.g. cart/checkout/product/category).
It is also hidden when Root.Page.Breadcrumbs.size > 2 (deeper navigation paths where the breadcrumb already provides context).
When the title block is visible (hide_div == false), the layout adds plain-page on the <body>.
Breadcrumbs#
The breadcrumb UI is always rendered from the layout:{% render 'Components\\Breadcrumb\\Default' %}
Breadcrumb data comes from Root.Page.Breadcrumbs.
Breadcrumb depth is also used by the layout to decide whether the H1/title block should be shown.
The footer is rendered after </main> and is composed via the footer component list.{% render 'Structure\\ComponentsList' with FooterComponents as components %}
Global UI / Modals outside main#
After <main>, the layout renders shared UI that should exist on all pages:Reusables\BackToTop\Default
Reusables\ProductComparisonFloatingButton\Default
Reusables\PromptModal\Default
Reusables\ProductModal\Default
Reusables\LoginModal\Default
Debugging helpers#
Near the end of the body, the layout includes:Structure\\StagingButton (staging/dev helper)
When the environment is staging, Structure\\StagingButton renders Structure\\Json to log a serialized view model in DevTools.This is very useful when validating component model contracts.Script loading order (very important)#
The layout loads scripts using defer to ensure predictable execution after parsing.Vendor libraries: axios, swiper, lightgallery, nouislider, flatpickr, leaflet, markercluster
/Themes/Noir/componentscripts.js
/Themes/Noir/Assets/js/theme.js
Why this matters#
componentscripts.js typically registers component/reusable JS objects.
theme.js contains shared utilities and Alpine stores used across components.
Alpine runs after the above are available.
Runtime globals injected into window#
LayoutA.liquid defines configuration flags used by client-side behavior:window.translations (example keys used by UI, e.g. Shopping Lists)
window.showProductComparison
These values are referenced by Assets/js/theme.js and various components/reusables.Recommendations#
Page title visibility: title block visibility depends on page type and breadcrumb size.
Global UI: modals/toast exist on every page by design; avoid duplicating them inside components.
Versioning: always keep version query params for asset updates to propagate correctly in cached environments.
Modified at 2026-06-12 12:25:17