Layout
Magewire is a large framework with many options and features. Still, the layout stays flexible — there is a documented extension point for injecting JavaScript, UI components, Alpine data, and every other piece of frontend wiring Magewire ships.
It's impossible to explain everything, and many parts are self-explanatory or include clear comments in the layout files. The sections below cover the containers and blocks you are most likely to target from a theme or a feature module.
The canonical source is src/view/base/layout/default.xml — the tree below mirrors it. Frontend and admin layouts add a small number of page-level moves on top (documented at the end).
Container tree
magewire (root block — Magewirephp_Magewire::root.phtml)
├── magewire.global (block)
│ ├── magewire.global.before (container)
│ │ ├── magewire.alpinejs.load ← Alpine JS <script> tag goes here
│ │ ├── magewire.alpinejs ← Alpine global functions, $wire
│ │ └── magewire.alpinejs.components ← Alpine.data(...) registrations
│ ├── magewire.utilities (block) ← MagewireUtilities.register(...)
│ │ └── magewire.utilities.after ← custom utilities render after core
│ ├── magewire.addons (block) ← MagewireAddons.register(...)
│ │ └── magewire.addons.after ← custom addons render after core
│ └── magewire.global.after
├── magewire.before (container) ← theme-owned directives / UI components
│ ├── magewire.alpinejs.directives ← custom Alpine directives
│ ├── magewire.ui-components ← notifier, dialogs, drawers, etc.
│ └── magewire.alpinejs.after ← Alpine code rendered AFTER Magewire's
├── magewire.before.internal ← runs before core internal blocks (rare)
├── magewire.internal (block) ← non-overridable framework internals
│ └── magewire.internal.backwards-compatibility ← v1 BC shims only
├── magewire.directives (block) ← wire:* directives (select, mage-notify, mage-throttle)
├── magewire.features (block) ← Feature bridge scripts
├── magewire.after.internal ← runs after core internal blocks (rare)
├── magewire.disabled (container) ← ONLY rendered when Magewire is disabled
├── magewire.after (container) ← last-to-render theme content
└── magewire.legacy (container)
└── magewire.plugin.scripts ← pre-v3 plugin compatibility
Frontend layout (src/view/frontend/layout/default.xml) adds on top:
<move element="magewire" destination="before.body.end"/>— moves the whole subtree to the end of<body>.magewire.alpinejs.components.magewire-scriptinsidemagewire.alpinejs.components— the Alpine component that boots Magewire's JS runtime.magewire.object-proxyinsideafter.body.start— early global object so inline snippets can queue work againstwindow.Magewire.
Admin layout (magewire-admin package) replaces the body-end move with a head-injection strategy — see Admin → How it works.
Containers
| Container / block | Type | Description |
|---|---|---|
magewire |
block | Root; wraps every Magewire-owned output. Do not replace its template — override children instead. |
magewire.global |
block | Global setup pass — runs once per page, before any per-feature wiring. |
magewire.global.before |
container | First region inside magewire.global. Used by the Alpine load, Alpine init, utilities, addons. |
magewire.global.after |
container | After-hook inside magewire.global. Empty by default — safe place for page-level hooks that must run after utilities / addons are registered. |
magewire.alpinejs.load |
container | Where Alpine's own <script> tag is rendered. Reorder or swap the Alpine bundle here. |
magewire.alpinejs |
container | Holds the block that defines Magewire's Alpine global (Alpine.data, Alpine.store). Targeted by themes that add global Alpine helpers. |
magewire.alpinejs.components |
container | Alpine.data(...) registrations. Each child block renders an <script> calling Alpine.data. |
magewire.before |
container | Everything that must precede Magewire's own directives/features. Theme-owned by convention. |
magewire.alpinejs.directives |
container | Custom x-* directive registrations. |
magewire.ui-components |
container | UI Alpine components — the core notifier lives here; theme overrides and additions too. |
magewire.alpinejs.after |
container | Alpine code that must load AFTER Magewire's Alpine wiring. |
magewire.before.internal |
container | Before Magewire's internal machinery. Reserved for framework use. |
magewire.internal |
block | Non-overridable core. Deliberately a block, not a container, so arbitrary injection is impossible. Inject via magewire.after.internal instead. |
magewire.internal.backwards-compatibility |
container | v1 BC shims only. Reserved. |
magewire.directives |
block | Magewire's own wire:* / mage-* directives (select, mage-notify, mage-throttle). |
magewire.features |
block | Feature-side bridge scripts (loaders, rate-limiting, etc.). One child per Feature by convention. |
magewire.after.internal |
container | After the internal block. Use when you must interleave with core internals. |
magewire.disabled |
container | Rendered ONLY when Magewire is disabled site-wide — surface a fallback or a warning here. |
magewire.after |
container | Last-to-render Magewire content. Theme-owned; safe default for theme-final output. |
magewire.utilities |
block | Loads window.MagewireUtilities and registers core utilities (dom, loader, str, cookie). |
magewire.utilities.after |
container | Inject custom utilities so they register after the core ones. |
magewire.addons |
block | Loads window.MagewireAddons and registers core addons (notifier). |
magewire.addons.after |
container | Inject custom addons so they register after the core ones. |
magewire.legacy |
container | BC shelf for v1 block/container names. |
magewire.plugin.scripts |
container | Pre-v3 plugin compatibility target. |
<referenceContainer> vs <referenceBlock>
<!-- Add a sibling block inside a container. Original children keep rendering. -->
<referenceContainer name="magewire.features">
<block name="magewire.features.my-bridge"
template="MyVendor_MyModule::magewire-features/my-bridge.phtml"/>
</referenceContainer>
<!-- Replace an existing block's template. Original template is gone. -->
<referenceBlock name="magewire.features.support-magewire-loaders"
template="MyVendor_MyModule::override-loaders.phtml"/>
Default to <referenceContainer>. Reach for <referenceBlock> only when you deliberately want to swap the template of a named block (for example, overriding the admin rate-limiting template with an admin-styled variant).
Ordering within a container
Magento layout XML honours after= / before= among siblings. For deterministic ordering inside a container:
<block name="magewire.features.my-bridge"
template="..."
after="magewire.features.support-magewire-loaders"/>
Do not rely on file load order — that depends on module sequence and is brittle.
Which container to target
| Goal | Target |
|---|---|
| Reorder or swap the Alpine bundle | magewire.alpinejs.load |
| Register a global JS helper (Magewire consumers) | magewire.utilities.after |
| Register an independent addon (e.g. notifier replacement) | magewire.addons.after |
Add an Alpine.data(...) component |
magewire.alpinejs.components |
Add a custom Alpine directive (x-*) |
magewire.alpinejs.directives |
Add a Magewire-level wire:* / mage-* directive |
magewire.directives |
| Bridge a Feature's JS counterpart | magewire.features |
| Inject theme-final content | magewire.after |
| Render a fallback when Magewire is disabled | magewire.disabled |
Directories & Templates
Magewire's src/view/base/templates/ directory is organised by the library the template targets — the path tells you what the template does before you open it.
Top-level directories
| Directory | Purpose |
|---|---|
js/ |
Templates whose primary payload is a <script> block. |
magewire/ |
PHTML UI templates (components and shared pieces) with negligible JS. |
magewire-features/ |
One subdirectory per registered Feature — bridge PHTML paired with magewire.features.* blocks. |
Under js/
| Directory | Purpose |
|---|---|
js/alpinejs/ |
Alpine-related templates. |
js/alpinejs/components/ |
Alpine .data(...) registrations — one file per component. |
js/alpinejs/directives/ |
Alpine x-* directive registrations. |
js/magewire/ |
Magewire runtime templates. |
js/magewire/addons/ |
One file per MagewireAddons.register(...) call (the notifier lives here). |
js/magewire/utilities/ |
One file per MagewireUtilities.register(...) call (dom, loader, str, cookie). |
js/magewire/directives/ |
Magewire-level directive registrations (select, mage-notify, mage-throttle). |
js/magewire/internal/ |
Non-overridable internals — do not add here from a module. |
Under magewire/
| Directory | Purpose |
|---|---|
magewire/ui-components/ |
Alpine-driven UI components (notifier, notifier activity state, …). |
magewire/utils/ |
Shared PHTML snippets consumed by other templates (icons, spinners). |
magewire/flakes/ |
Flake templates — see Magewire Flakes. |
Under magewire-features/
Each Feature gets its own kebab-cased subdirectory matching its container name. For example:
magewire-features/
├── support-magewire-loaders/
│ └── support-magewire-loaders.phtml
└── support-magewire-rate-limiting/
└── support-magewire-rate-limiting.phtml
Pair a child block under magewire.features with a template in Vendor_Module::magewire-features/<kebab-name>/<kebab-name>.phtml. The admin rate-limiting override in magewire-admin follows the same convention — reuse it in your own theme modules.
Building something custom or making a contribution? Always examine the folder and file structure closely to ensure you're in the right location.
Blocks that look like containers
magewire.internal, magewire.directives, magewire.features, magewire.utilities, and magewire.addons are blocks, not containers — each has a template that renders a scaffold around its children. Two practical consequences:
- You cannot
<referenceContainer name="magewire.features">and expect it to work in every context — Magento is picky about container vs. block reference types.<referenceBlock>works for both when you only need to add children, but prefer the correct tag for the target. - To completely swap the scaffold (e.g. a different wrapper for all directives), override the template with
<referenceBlock name="magewire.directives" template="..."/>. Rare; only do this when the parent's markup genuinely needs replacing.
Off-limits from a theme
magewireroot block itself — do not replace its template.magewire.internaland anything directly under it (except the BC sub-container) — reserved for core.magewire.before.internal/magewire.after.internal— used only when the framework's own internal ordering requires it.
If a container you need doesn't exist, add one in default_{theme}.xml as a child of an existing container rather than repurposing a reserved one.
Page-specific vs global overrides
default_{theme}.xml— applies on every page where the theme is active. Use for load-order fixes, global Feature bridges, BC shims.{route}_{controller}_{action}.xml— applies on one route only. Use for page-scoped Features (for example, Hyvä Checkout's BC feature is activated only onhyva_checkout_index_index).
Smaller scope is cheaper — page-specific handles avoid paying for the block on every page.