npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nipe-solutions/react-viewport

v0.1.0-alpha.0

Published

Reactive React viewport geometry for layout, visual viewport, keyboards, and safe areas.

Readme

@nipe-solutions/react-viewport

Reliable mobile viewport state for React.

@nipe-solutions/react-viewport exposes reactive layout viewport, visual viewport, keyboard-occlusion, and safe-area geometry. It is intended for the application behavior that CSS cannot express by itself, such as a composer that must respond to a measured keyboard occlusion.

Alpha software: 0.1.0-alpha.0 is an early release. Its API and browser behavior may change. Physical-device QA is still pending; see docs/REAL_DEVICE_QA.md. Measured automated-release evidence and deployment status are recorded in the 0.1.0-alpha.0 readiness report.

Installation

npm install @nipe-solutions/react-viewport

The package has no runtime dependencies. It supports React and React DOM ^18.3.0 || ^19.0.0, ships ESM, CommonJS, and TypeScript declarations, and requires Node.js >=24 <25 for repository development.

Quick start

import { useViewport } from '@nipe-solutions/react-viewport'

export function ViewportReadout() {
  const viewport = useViewport()

  if (!viewport.ready || viewport.visual === null) {
    return <p>Measuring viewport…</p>
  }

  return (
    <p>
      Visible size: {viewport.visual.width} × {viewport.visual.height}; keyboard:{' '}
      {viewport.keyboard.open ? `${viewport.keyboard.height}px` : 'closed'}
    </p>
  )
}

No provider is required for normal use. Use ViewportProvider only to scope a subtree to an accessible, same-origin Window, such as an iframe or test window. A cross-origin window cannot expose the document APIs this package measures. Passing targetWindow={null} intentionally supplies the stable server snapshot (ready: false) to descendants.

import { ViewportProvider } from '@nipe-solutions/react-viewport'

export function EmbeddedViewport({ childWindow }: { childWindow: Window | null }) {
  return <ViewportProvider targetWindow={childWindow}>{/* descendants */}</ViewportProvider>
}

Layout viewport versus visual viewport

The Layout viewport is window.innerWidth and window.innerHeight: the coordinate space used for layout. The Visual viewport is the currently visible region. When window.visualViewport is available, it also has offsets, page coordinates, and a scale. A soft keyboard, browser UI, or pinch zoom can change the visual viewport without changing the layout viewport.

The API intentionally keeps those coordinate systems separate:

const { layout, visual, keyboard, safeArea, supported } = useViewport()

On a client without window.visualViewport, visual falls back to layout geometry with zero offsets, page coordinates from window scroll, and scale 1. supported.visualViewport records that this is fallback geometry rather than a native VisualViewport reading.

Keyboard state is conservative

keyboard.height is the estimated or reported bottom viewport occlusion caused by the software keyboard. It is not the physical keyboard's full rectangular height.

Detection follows a deliberately short hierarchy:

  1. Native Virtual Keyboard geometry is authoritative when available.
  2. Otherwise, conservative VisualViewport inference can report an occlusion.
  3. When the evidence is insufficient, the library reports no keyboard.

The fallback infers an occluding software keyboard only when an editable element is focused, zoom is not active, and visual-bottom occlusion crosses max(80 CSS px, 15% of layout height). The keyboard-closed baseline is only an evidence gate: reported fallback height is always the current max(0, layout.height - (visual.height + visual.offsetTop)). If layout and visual height shrink together with no current bottom occlusion, the keyboard remains closed. Focus alone never means that a software keyboard is open. This deliberate heuristic can miss small, floating, or split keyboards; treat keyboard as measured or inferred geometry, not a device-level keyboard guarantee.

CSS variables

For CSS-driven positioning, install variables on the document root (the default) or on a chosen element:

import { useViewportCssVariables } from '@nipe-solutions/react-viewport'

export function App() {
  useViewportCssVariables()
  return <main>…</main>
}
.composer {
  position: fixed;
  right: max(1rem, var(--react-viewport-safe-area-right, 0px));
  bottom: calc(
    var(--react-viewport-keyboard-height, 0px) +
      max(1rem, var(--react-viewport-safe-area-bottom, 0px))
  );
  left: max(1rem, var(--react-viewport-safe-area-left, 0px));
}

The hook writes these client-side variables: layout and visual width/height, visual offsets/page positions/scale, keyboard height, and four safe-area inset lengths. Dimensional variables such as --react-viewport-layout-height are removed until the first measurement, rather than populated with made-up server values. Multiple live hooks coordinate ownership per target property: the last-mounted owner supplies values, and the last owner to leave restores the latest consumer value observed before a library write. A stable ref target may start null, be replaced, or detach; ownership and subscriptions migrate after the corresponding React commit without stale writes to the previous element.

Non-zero env(safe-area-inset-*) values generally require the page viewport to opt into viewport-fit=cover. Configure that metadata before relying on the package's measured safeArea values; unsupported or zero-inset environments truthfully report zero.

SSR and hydration

Server rendering is safe: importing the package and calling useViewport do not access browser globals. The stable server snapshot has ready: false, null layout and visual values, a closed zero-height keyboard, zero safe-area insets, and false support flags. Render a safe placeholder for geometry-dependent UI until ready is true to avoid assumptions during SSR and hydration.

When CSS is enough

Prefer CSS when the browser can express the behavior directly. Use dvh, svh, and lvh for viewport-relative sizing; use env(safe-area-inset-*) for safe area padding; and use media/container queries for responsive layout. This library is for React behavior that needs measured geometry or an explicit layout-versus-visual distinction. It is not a breakpoint, device-detection, scroll-locking, focus-management, modal, or general mobile-layout library.

Browser terminology and limitations

Supported means the runtime can detect an API on the current browser. Tested means a deterministic repository scenario covers a behavior in the configured Chromium, Firefox, or WebKit projects. Fallback means the package uses documented alternate geometry when an optional API is absent. These labels are different from physical-device verification.

The project does not claim universal browser support. In particular:

  • Browser APIs cannot reliably distinguish every floating or split keyboard.
  • The fallback inference intentionally favors false negatives over moving UI for ordinary browser chrome changes.
  • Desktop automation cannot reproduce physical mobile browser chrome or keyboard animations exactly.
  • Embedded WebViews can expose different viewport behavior and need host-level verification.
  • Foldable viewport segments and synthetic keyboard animations are outside v1.

See docs/browser-notes.md for the browser-note registry and docs/REAL_DEVICE_QA.md for the current physical-device matrix.

Project

Part of NIPE Open Source