viewport-truth Svelte Themes

Viewport Truth

Tiny zero‑config VisualViewport-first store for accurate visible viewport size in CSS pixels. Detects virtual keyboard, stabilizes resize/scroll jitter, and is SSR-safe across frameworks.

viewport-truth

Fastest way to measure the real visible mobile viewport without 100vh glitches, resize/scroll jitter, or keyboard hacks.

Stop guessing mobile viewport sizes. viewport-truth delivers stable, keyboard-aware visible viewport metrics (VisualViewport-first) across iOS Safari, Android Chrome, PWAs, and webviews—framework adapters included, SSR-safe, zero runtime deps.

npm i viewport-truth
# or: yarn add viewport-truth
# or: pnpm add viewport-truth

Quick Start

Minimal flow: import → create → subscribe → get { width, height, isKeyboardOpen, isStable }.

import { createViewportTruth } from "viewport-truth/vanilla";

const vt = createViewportTruth();

const unsub = vt.subscribe((v) => {
    if (!v) return;

    console.log(
        `visible=${v.width}x${v.height} keyboard=${v.isKeyboardOpen} stable=${v.isStable}`
    );
});

// later:
// unsub();
// vt.destroy();

Wow example (keyboard eats UI… and you can see it)

A tiny bottom bar that stays visible and shows exactly how much viewport you lost.

Run it in a real page (Vite/Parcel/Next) — the snippet won’t execute inside README.
On mobile: scroll a bit (URL bar), then focus the input (keyboard).

<div id="app" style="padding:16px 16px 96px">
  <input
    placeholder="Focus me to open keyboard"
    style="width:100%;padding:12px;font-size:16px;box-sizing:border-box"
  />
  <p style="margin:12px 0 0;color:#444">
    Tip: scroll a bit (URL bar animates), then focus the input.
  </p>

  <div style="height:120vh"></div>
  <div id="bar"></div>
</div>

<script type="module">
  import { createViewportTruth } from "viewport-truth/vanilla";

  const bar = document.getElementById("bar");
  Object.assign(bar.style, {
    position: "fixed",
    left: "0",
    right: "0",
    bottom: "0",
    padding: "10px 12px",
    font: "12px/1.35 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
    background: "rgba(0,0,0,.86)",
    color: "white",
    zIndex: "9999",
    whiteSpace: "pre",
  });

  const vt = createViewportTruth();

  vt.subscribe((v) => {
    if (!v) return;

    // Fallback keeps the snippet working even if layoutWidth/layoutHeight aren't present.
    const layoutW = v.layoutWidth ?? v.width;
    const layoutH = v.layoutHeight ?? v.height;

    const lost = Math.max(0, layoutH - v.height);

    bar.textContent =
`visible:  ${v.width}×${v.height}
layout:   ${layoutW}×${layoutH}
lost:     ${lost}px
keyboard: ${v.isKeyboardOpen}
stable:   ${v.isStable}`;
  });
</script>

Features

A few concrete, technical reasons it behaves well on mobile:

  • Tiny: ~< 2 KB min+gzip (check the Bundlephobia badge).
  • Fast updates: emits at most 1 update per animation frame (rAF throttling).
  • Zero runtime deps: 0 dependencies at runtime (tree-shakeable ESM).
  • Stable signal: isStable flips after 150ms (default) without geometry changes.

API (short)

Core snapshot fields you’ll typically use:

  • width, height — visible viewport size (CSS px)
  • layoutWidth, layoutHeight — layout viewport (basis for keyboard detection)
  • isKeyboardOpen — geometry-based keyboard inference
  • isStable — “animations settled” signal for UI decisions

Vanilla store:

  • createViewportTruth() from viewport-truth/vanilla → creates a store with subscribe() and destroy()

Framework adapters:

  • React: useViewportTruth from viewport-truth/react
  • Vue: useViewportTruth from viewport-truth/vue
  • Svelte: viewportTruth from viewport-truth/svelte
  • Solid: createViewportTruth from viewport-truth/solid
  • Angular: ViewportTruthDirective from viewport-truth/angular

Full types and signatures: see dist/*.d.ts (or TypeScript IntelliSense).

Adapter Docs: ReactVueSvelteSolidAngular

Tip: Open links in a new tab with Ctrl+Click (Windows/Linux) or Cmd+Click (macOS).

FAQCommon pitfallsSmoke test (clean environment)Versioning policy

Support the project

“We ate the Geometry Hell for you: jumping 100vh, jittery resize, modals under the keyboard.
You saved hours (and sanity). A donation is a fair trade for a rock-solid UI and weekends free from debugging.”

If this library saved you time, please consider supporting the development:

  1. Fiat (Cards/PayPal): via Boosty (one-time or monthly).
  2. Crypto (USDT/BTC/ETH): view wallet addresses on Telegram.

License

MIT

Top categories

Loading Svelte Themes