Recipes
Cross-feature compositions for @mongez/dom.
Per-page metadata in a SPA
Drive the page’s <head> from the router. setPageMeta is idempotent — call it on every route change, no special teardown needed.
import { setPageMeta } from "@mongez/dom";
function applyRouteMeta(route: { title: string; description: string; path: string }) { setPageMeta({ title: route.title, description: route.description, url: `https://example.com${route.path}`, type: "website", });}
router.on("change", applyRouteMeta);In React, do the same inside a top-level effect:
useEffect(() => applyRouteMeta(currentRoute), [currentRoute.path]);Multi-weight font loading + CSS
googleFont if you’re OK with the network-hosted CSS; loadFont if you want to bundle the woff2 files and load them via FontFace.
import { loadFont, cssVariable } from "@mongez/dom";import light from "./fonts/inter-300.woff2";import regular from "./fonts/inter-400.woff2";import bold from "./fonts/inter-700.woff2";
await loadFont({ name: "Inter", weights: [ { weight: "light", woff2: light }, { weight: "normal", woff2: regular }, { weight: "bold", woff2: bold }, ],});
cssVariable("--font-base", '"Inter", system-ui, sans-serif');Then in CSS:
:root { font-family: var(--font-base); }.headline { font-weight: 700; }.caption { font-weight: 300; }Dark-mode theming via CSS variables
import { cssVariable, userPrefersDarkMode } from "@mongez/dom";
function applyTheme() { const dark = userPrefersDarkMode(); cssVariable("--color-bg", dark ? "#0a0a0a" : "#ffffff"); cssVariable("--color-fg", dark ? "#ededed" : "#111111"); cssVariable("--color-link", dark ? "#7cf" : "#06c");}
applyTheme();
const mq = window.matchMedia("(prefers-color-scheme: dark)");mq.addEventListener("change", applyTheme);Theme switcher with styleSheet
For the case where two whole stylesheets define light/dark themes, swap the href of a single <link>:
import { styleSheet } from "@mongez/dom";
const LIGHT = "/themes/light.css";const DARK = "/themes/dark.css";
styleSheet(LIGHT, "theme");
function setTheme(mode: "light" | "dark") { styleSheet(mode === "dark" ? DARK : LIGHT, "theme");}The id="theme" makes both calls hit the same <link> — no duplicate tags.
Smooth-scrolling table of contents
import { scrollTo } from "@mongez/dom";
document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener("click", e => { e.preventDefault(); scrollTo(anchor.getAttribute("href")!); });});If the URL hash should update too:
anchor.addEventListener("click", e => { e.preventDefault(); const hash = anchor.getAttribute("href")!; scrollTo(hash); history.pushState(null, "", hash);});Keyboard shortcut handler
import { pressed, ESC_KEY, ENTER_KEY } from "@mongez/dom";
function dialogShortcuts(dialog: HTMLElement, onSubmit: () => void, onCancel: () => void) { function onKey(e: KeyboardEvent) { if (pressed(e, ENTER_KEY)) { e.preventDefault(); onSubmit(); } else if (pressed(e, ESC_KEY)) { e.preventDefault(); onCancel(); } } dialog.addEventListener("keydown", onKey); return () => dialog.removeEventListener("keydown", onKey);}Append a third-party script when consent is granted
import { loadScript } from "@mongez/dom";
let analyticsLoaded = false;
function loadAnalyticsOnce() { if (analyticsLoaded) return; analyticsLoaded = true; loadScript("https://example.com/analytics.js", () => { (window as any).analytics.init("KEY"); });}
consentBanner.addEventListener("accept", loadAnalyticsOnce);loadScript doesn’t dedupe internally; the local flag prevents accidental double-injection.
Compose a per-article meta head
Beyond the setPageMeta defaults — author, published_time, locale alternates:
import { setPageMeta, meta, metaLink } from "@mongez/dom";
function setArticleMeta(article: { title: string; description: string; url: string; image: string; author: string; publishedAt: string; locales: { code: string; href: string }[];}) { setPageMeta({ title: article.title, description: article.description, url: article.url, image: article.image, type: "article", }); meta("article:author", article.author); meta("article:published_time", article.publishedAt); for (const l of article.locales) { metaLink("alternate", l.href, { hreflang: l.code }); }}Viewport-driven decisions
import { getScreenWidth } from "@mongez/dom";
function isMobile() { return getScreenWidth() < 768;}Note this reads window.screen.width, which is the monitor size — not the resized browser window. For the visible viewport use window.innerWidth directly.
HTML excerpt for previews
import { htmlToText } from "@mongez/dom";
function excerpt(html: string, length = 160): string { const text = htmlToText(html).trim().replace(/\s+/g, " "); return text.length > length ? text.slice(0, length - 1) + "…" : text;}