Read one snapshot, keep the meanings separate
ready becomes true after the first client measurement. Until then, layout, visual, and orientation are null. A false readiness value describes timing, not browser support.
Layout is the page's CSS-pixel reference plane. Visual size and offsets describe the region currently visible inside that plane; page coordinates describe its document position. Native VisualViewport values are used when available, otherwise the documented layout fallback supplies visual geometry.
supported.virtualKeyboard means API availability, not that overlay mode is active or a keyboard is visible. The package reads intersection geometry but never enablesoverlaysContent mode. Keyboard height is bottom occlusion, not the on-screen keyboard's full rectangle.
Safe-area values are raw edge insets. To position bottom UI against both constraints, use Math.max(keyboard.height, safeArea.bottom); do not add them.
Runtime
Hooks use a shared useSyncExternalStore store per window. The server snapshot is stable and geometry-neutral. Pass targetWindow only after verifying that an alternate iframe or popup is same-origin and its Window is accessible; coordinates and DOM rectangles must come from that same window.
useViewport()
Subscribes to the current window, or to the window supplied by the nearest ViewportProvider.
export declare function useViewport(): ViewportState;useViewportCssVariables()
Writes current geometry to options.target, or to the document root when target is omitted. The target can be an HTMLElement, a React ref, or null.
export declare function useViewportCssVariables(options?: ViewportCssVariablesOptions): void;<ViewportProvider>
Renders children and scopes descendants to targetWindow. Omitting targetWindow uses the global window; passing null intentionally selects the server snapshot.
export declare function ViewportProvider({ children, targetWindow, }: ViewportProviderProps): React.ReactNode;Types
LayoutViewport
The layout viewport width and height from window.innerWidth and window.innerHeight, in CSS pixels. This is the page reference plane, not a guarantee that the whole region is visible or unobstructed.
export interface LayoutViewport {
readonly width: number;
readonly height: number;
}VisualViewportState
The visible viewport size, layout-relative offsets, document-relative page coordinates, and scale. Values come from VisualViewport when supported and from the documented layout fallback otherwise; a change does not identify its cause as a keyboard.
export interface VisualViewportState {
readonly width: number;
readonly height: number;
readonly offsetTop: number;
readonly offsetLeft: number;
readonly pageTop: number;
readonly pageLeft: number;
readonly scale: number;
}KeyboardState
open records sufficient native or fallback evidence of a software keyboard. height is bottom-edge occlusion, not the on-screen keyboard's full rectangle. A native floating intersection can be open: true, height: 0.
export interface KeyboardState {
readonly open: boolean;
readonly height: number;
}SafeAreaInsets
Raw top, right, bottom, and left CSS safe-area environment measurements in CSS pixels. They are not automatically keyboard-aware and must not be added to keyboard occlusion.
export interface SafeAreaInsets {
readonly top: number;
readonly right: number;
readonly bottom: number;
readonly left: number;
}ViewportOrientation
Portrait or landscape derived from the layout viewport aspect ratio. This is not a device-orientation sensor reading.
export type ViewportOrientation = 'portrait' | 'landscape';ViewportSupport
Runtime API-presence flags. visualViewport distinguishes native from fallback visual geometry; virtualKeyboard means navigator.virtualKeyboard exists, not that overlay mode is active or a keyboard is currently detected.
export interface ViewportSupport {
readonly visualViewport: boolean;
readonly virtualKeyboard: boolean;
}ViewportState
One immutable snapshot. ready becomes true after the first client measurement; before that, layout, visual, and orientation are null while keyboard and safe-area values remain safe zeroes.
export interface ViewportState {
readonly ready: boolean;
readonly layout: LayoutViewport | null;
readonly visual: VisualViewportState | null;
readonly keyboard: KeyboardState;
readonly safeArea: SafeAreaInsets;
readonly orientation: ViewportOrientation | null;
readonly supported: ViewportSupport;
}ViewportProviderProps
Scopes descendants to an accessible same-origin Window. Omission uses the global window; null intentionally selects the server snapshot.
export interface ViewportProviderProps {
readonly children: React.ReactNode;
readonly targetWindow?: Window | null;
}ViewportCssVariablesOptions
Chooses the HTMLElement or React ref that receives variables. Omission or null targets the document root; a ref whose current value is null has no target until it attaches.
export interface ViewportCssVariablesOptions {
readonly target?: HTMLElement | React.RefObject<HTMLElement | null> | null;
}CSS variables
Lengths serialize as CSS pixels; scale is unitless. Dimensional values are absent until the first client measurement. This hook bridges shared measurements into CSS; CSS still owns layout and the application still owns policy.
--react-viewport-layout-width--react-viewport-layout-height--react-viewport-visual-width--react-viewport-visual-height--react-viewport-visual-offset-top--react-viewport-visual-offset-left--react-viewport-visual-page-top--react-viewport-visual-page-left--react-viewport-scale--react-viewport-keyboard-height--react-viewport-safe-area-top--react-viewport-safe-area-right--react-viewport-safe-area-bottom--react-viewport-safe-area-left