Skip to content

data-match-media

Keep a boolean signal in sync with a media query, updating when the viewport or a system preference changes. The value is the query itself, written as you would in CSS.

data-match-media:is-dark="prefers-color-scheme: dark"
data-match-media:wide="(min-width: 60rem)"
data-match-media:print="print"
data-match-media:narrow__dynamic="'(max-width: ' + $breakpoint + 'px)'"
part
key required: the signal path (camelCased, __case changes it)
value required: the media query, a literal
modifier effect
__dynamic evaluate the value as an expression; the query follows the signals it reads
__case.kebab keep the key kebab-cased

Resize the window or switch your system theme: the values follow.

three queries
narrow viewport: , dark scheme: , reduced motion:
<div data-match-media:narrow="max-width: 700px" data-match-media:dark="prefers-color-scheme: dark" data-match-media:reduced="prefers-reduced-motion: reduce">
narrow viewport: <b data-text="$narrow"></b>, dark scheme: <b data-text="$dark"></b>, reduced motion: <b data-text="$reduced"></b>
</div>

Anything reactive can read it: show a compact menu on narrow screens, a full one otherwise.

responsive markup

Narrow the window below 700px to swap the nav for a select.

<div data-match-media:compact="max-width: 700px">
<nav data-show="!$compact" class="row"><a href="#">Home</a> <a href="#">Docs</a> <a href="#">Blog</a> <a href="#">About</a></nav>
<select data-show="$compact"><option>Home</option><option>Docs</option><option>Blog</option><option>About</option></select>
<p class="muted">Narrow the window below 700px to swap the nav for a select.</p>
</div>

With __dynamic the value is an expression, so the breakpoint can live in a signal.

__dynamic
breakpoint

viewport narrower than that:

<div data-signals="{ bp: 900 }" data-match-media:below__dynamic="'(max-width: ' + $bp + 'px)'">
<div class="row"><input type="range" min="300" max="1600" step="50" data-bind:bp> breakpoint <b data-text="$bp + 'px'"></b></div>
<p>viewport narrower than that: <b data-text="$below"></b></p>
</div>

Bare feature: value pairs are wrapped in parentheses for you; full media queries such as screen and (min-width: 60rem), print or (orientation: landscape) are passed through unchanged. The signal is written once on mount and again on every change of the MediaQueryList; with __dynamic, a new query replaces the old listener.

import { matchMedia } from 'sigmx/plugins'

Registering matchMedia adds 204 bytes brotli (235 gzip, 471 minified) on top of the core. See bundle sizes.