Skip to content

Get Started with Crows Nest

Getting started with Crows Nest is quick and easy. Just follow the steps below and you'll be up and running in no time.

Installation

You can install @nhtio/crows-nest directly from your preferred package manager

sh
npm i @nhtio/crows-nest
sh
pnpm add @nhtio/crows-nest
sh
yarn add @nhtio/crows-nest

Initialize the Crows Nest

typescript
import { CrowsNest } from '@nhtio/crows-nest'

const nest = new CrowsNest()

Options

CrowsNest accepts an optional options object:

typescript
const nest = new CrowsNest({
  // Called for each internal debug message.
  onDebug: (...args) => console.debug(...args),
  // Enable the VirtualKeyboard API's overlay mode so the on-screen keyboard
  // shrinks the observable safe area (rather than resizing the whole layout
  // viewport). Defaults to `true`. Set to `false` to keep control of
  // `navigator.virtualKeyboard.overlaysContent` in your own app.
  overlaysContent: true,
  // How a manually-pushed keyboard state (see "Pushing keyboard state manually")
  // interacts with Crows Nest's own detection: 'latch' (default) hands control to
  // the consumer after the first manual event; 'nudge' sets it once and lets the
  // next automatic recompute override it.
  manualKeyboardControl: 'latch',
})

For backwards compatibility a bare debug callback is still accepted: new CrowsNest((...args) => console.debug(...args)).

Keyboard note: on browsers that support the VirtualKeyboard API (e.g. Chrome on Android), overlaysContent: true is what lets Crows Nest detect the keyboard and reflect it in observable.offset.bottom and the keyboard state. When it is false, or on browsers without the API (e.g. iOS Safari), keyboard presence is inferred from the visual viewport instead.

Pushing keyboard state manually

Browser keyboard detection is imperfect. A native or hybrid shell (e.g. a Capacitor app using @capacitor/keyboard) often knows the on-screen keyboard state authoritatively. You can push that state into Crows Nest by dispatching a CROWS_NEST_KEYBOARD_EVENT CustomEvent on window:

typescript
import { CROWS_NEST_KEYBOARD_EVENT } from '@nhtio/crows-nest'

// e.g. from @capacitor/keyboard
Keyboard.addListener('keyboardWillShow', () => {
  window.dispatchEvent(
    new CustomEvent(CROWS_NEST_KEYBOARD_EVENT, { detail: { state: 'open' } })
  )
})
Keyboard.addListener('keyboardWillHide', () => {
  window.dispatchEvent(
    new CustomEvent(CROWS_NEST_KEYBOARD_EVENT, { detail: { state: 'closed' } })
  )
})

Crows Nest updates nest.keyboard and emits the usual keyboard.changed / keyboard.opened / keyboard.closed events. With the default manualKeyboardControl: 'latch', the first manual event makes the consumer the source of truth (Crows Nest stops its own keyboard heuristic); use 'nudge' if you only want to correct the state occasionally.

Bind an Element to your nest

Binding an element makes it track the observable safe area — it is positioned and sized to stay clear of the display shape (notch / Dynamic Island), the PWA title bar, and the virtual keyboard.

typescript
const bound = document.getElementById("bound")
nest.bindHtmlElement(bound)

To stop tracking an element, unbind it:

typescript
nest.unbindHtmlElement(bound)

Tear down the nest

Crows Nest attaches viewport listeners and observers to the document. When you are finished with an instance (for example, when a component unmounts), call destroy() to remove them and avoid leaking listeners:

typescript
nest.destroy()

destroy() is idempotent — calling it more than once is safe.