Viewport geometry you can reason about: what the browser lays out, what a person can see, and what may cover the edges.
Four measurements, four jobs
Layout viewport
The page’s coordinate space, measured by the browser window.
Visual viewport
The part of that layout currently visible, including its offsets and scale.
Keyboard occlusion
The bottom edge covered by a software keyboard, when evidence supports it.
Safe area
Protected edge insets exposed by CSS for hardware and browser UI.
What changes, and why
The layout viewport is the reference plane. Browser chrome can move and shorten the visual viewport; a software keyboard can leave part of the layout covered; pinch zoom changes the visual size, offsets, and scale. Those causes can look similar if an interface watches height alone.
Bottom occlusion therefore includes the visual viewport’s top offset and never goes below zero:
keyboard.open means the library has sufficient evidence that a software keyboard is visible. It does not mean that an input merely has focus, and the package does not use it to show, hide, or resize the keyboard.
Native keyboard geometry is used when available. Otherwise, inference requires an editable focus, approximately unit scale, and a keyboard-sized current bottom occlusion. Browser chrome, zoom, and hardware-keyboard-like focus remain closed.
Safe area and keyboard occlusion stay raw and independent. For bottom UI, use the larger constraint—Math.max(keyboard.height, safeArea.bottom)—instead of adding two values that may describe the same covered edge.
Read the scenarios
Normal
The layout and visual viewports match. Nothing is occluded; keyboard status is closed.
Browser chrome
The visible region shifts and shrinks because of browser UI; keyboard status is closed.
Soft keyboard
A focused editable and 300 px bottom occlusion provide enough evidence; keyboard status is open.
Shifted keyboard
The 28 px top offset is included, leaving 300 px occluded; keyboard status is open.
Zoom
Scale explains the smaller visible region, so keyboard status remains closed.
Custom
Every value is editable. Contradictory keyboard and visual geometry produces a warning instead of pretending the state is typical.
LIVE BROWSER
One screen, four measured regions
Compare what changes in each browser state and why. Layout, visual viewport, keyboard occlusion, and safe area stay separate.
Awaiting client geometry
Origin 0,0 · one unit equals one CSS pixel before diagram scaling
Imports and server renders do not read browser globals. Server rendering and the first hydration pass share a stable snapshot with ready: false and no layout or visual geometry. Render a geometry-neutral placeholder until the first client measurement.
Shared-store performance
Subscribers targeting the same window share one store, browser listener set, and safe-area probe. Events are coalesced into one animation-frame measurement, and an unchanged scalar snapshot does not notify React again.
CSS-variable consumers subscribe to that store directly. This describes the measured lifecycle; it is not a throughput or CPU benchmark.
What not to do
Do not use layoutHeight - visualHeight for bottom occlusion; it ignoresvisualOffsetTop.
Do not add keyboard height to the safe-area bottom; use the larger constraint.
Do not treat focus or visual viewport shrinkage alone as an open keyboard.
Do not render client geometry as known before the first measurement is ready.