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
npm i @nhtio/crows-nestpnpm add @nhtio/crows-nestyarn add @nhtio/crows-nestInitialize the Crows Nest
import { CrowsNest } from '@nhtio/crows-nest'
const nest = new CrowsNest()Options
CrowsNest accepts an optional options object:
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: trueis what lets Crows Nest detect the keyboard and reflect it inobservable.offset.bottomand thekeyboardstate. When it isfalse, 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:
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.
const bound = document.getElementById("bound")
nest.bindHtmlElement(bound)To stop tracking an element, unbind it:
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:
nest.destroy()destroy() is idempotent — calling it more than once is safe.