Mobile block variants — m. prefix
A block file whose name starts with
m.
is the
mobile variant
of the block beside it. The server picks between the two per request, before a byte of HTML is
sent, from the same
$device.mobile
a template reads. Use it when a phone needs a structurally different page — different
navigation, a different interaction model — not merely a restyled one. For restyling,
reach for gale's breakpoint variants (md:flex) first.
implementation/apps/docs/
└─ blocks/
├─ mobile-blocks.html → /mobile-blocks (desktop)
├─ mobile-blocks.mjs → its controller
├─ m.mobile-blocks.html → /mobile-blocks (mobile)
└─ m.mobile-blocks.mjs → ITS controller
One registered route. Two files. The server picks per request.
Previewing the variant
Chrome / Edge:
open devtools and toggle
device mode
(the phone icon). Chromium then sends
Sec-CH-UA-Mobile: ?1, which settles it outright — reload
and this page becomes its mobile twin.
Firefox / Safari:
those browsers send no client hints, so narrow the window below
600px
and reload
twice. The runtime writes your viewport into the
cnc_vp
cookie on mount, so the server learns it from the second request on — the first reload
after resizing still renders desktop. That flip happens between requests, never mid-page.
No
m.
file means the plain block serves every viewer. The variant is a whole block, with its own
controller:
// blocks/mobile-blocks.mjs — runs for desktop viewers
export default {
layout: 'two-column',
async $save(draft) { /* the desktop flow */ },
}
// blocks/m.mobile-blocks.mjs — runs for mobile viewers
export default {
layout: 'stacked',
async $save(draft) { /* the phone flow, whatever it needs to be */ },
}
Blocks only. A widget has no mobile variant —
variant
is resolved statically at render time and cannot respond to a viewport. Inside either file,
$device
is still readable as usual.