# Hostee

Hostee-side SDK for feature apps: feature initialization, contract declaration, and lifecycle.

```ts
import { createFeature } from '@hyperfrontend/features/hostee'

const feature = createFeature({
  name: 'clock',
  contract: {
    emitted: [{ type: 'tick' }],
    accepted: [{ type: 'set-timezone' }],
  },
})

await feature.ready()
feature.on('set-timezone', ({ tz }) => render(tz))
setInterval(() => feature.send('tick', Date.now()), 1000)
```

## API

| Export                                                                                             | Purpose                                                                                                                                                                                                                                                                                                                                                                                                             |
| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`createFeature`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-createFeature) | Connect a feature app to its host; returns [`send`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle)/[`on`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle)/[`ready`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle)/[`close`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle). |
| [`FeatureHandle`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle) | Type of the handle returned by [`createFeature`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-createFeature); carries [`hosted`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle-prop-hosted) and [`displayMode`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle-prop-displayMode) too.                                       |

`ready()` resolves once the wire handshake with the host completes, and rejects if the host does not open the connection within [`readyTimeoutMs`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureOptions-prop-readyTimeoutMs) (default 10 s; an [`error`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle) with `reason: 'ready-timeout'` is also emitted). Sends issued before the handshake completes queue and flush on open. [`send`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle) emits a contract action to the host; [`on`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle) subscribes to host messages and the [`open`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle)/[`closing`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle)/[`close`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle)/[`error`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle)/[`presentation`](https://www.hyperfrontend.dev/docs/libraries/features/#api-PresentPayload)/[`resize`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-ViewportPayload) lifecycle events ([`closing`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle) is the flush window before a polite close completes). [`setDirty`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle) declares unsaved work to the host. [`close`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle) disconnects from the host politely.

## Presentation

The host owns how the feature is surfaced; the SDK receives that decision and prepares the document, so the app author only has to make the layout responsive.

Right after [`open`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle), the host announces the display mode along with the frame's initial dimensions: read the mode from [`feature.displayMode`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle-prop-displayMode) or the [`presentation`](https://www.hyperfrontend.dev/docs/libraries/features/#api-PresentPayload) event (`{ mode }`); the dimensions arrive as the first [`resize`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-ViewportPayload) event, no extra round trip. In the iframe modes the host then reports every change to the frame's usable space as exact pixels; the SDK sizes `html`/`body` to match and re-emits each as [`resize`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-ViewportPayload) (`{ width, height }`). In [`popup`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-DisplayMode)/[`standalone`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-DisplayMode) the browser window is the viewport and [`resize`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-ViewportPayload) comes from the feature's own window. Responding to the reported width and height (media/container queries, reflow, breakpoints) is the app author's job.

In **dialog** mode the frame spans the host's viewport, transparent. The SDK places your root element (the body's first element child, or pass [`root`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureOptions-prop-root) to [`createFeature`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-createFeature)) at the agreed position (centered by default) and sizes it to the agreed inner-box dimensions; everything around it is the backdrop. You style the box itself (background, border, shadow) since an unstyled box is invisible against the transparent backdrop.

The SDK detects pointer interaction on the bare backdrop and Escape presses and reports them to the host as dismiss signals, pure reports: the SDK tears nothing down itself, and if the host's policy is to close, the ordinary polite close ([`closing`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle) flush window included) follows. Because the pane covers the whole viewport, dragging or resizing the box is ordinary in-document CSS/pointer work if you want it: nothing crosses the boundary.

The body reset ([`resetBody`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureOptions-prop-resetBody), on by default) keeps `html`/`body` margin-free and **transparent**, with a `color-scheme` pin matched to the host frame: overriding the background or `color-scheme` with an opaque/dark scheme breaks the transparency that embedded blending and dialog backdrops depend on.

It applies on a direct top-level visit too: the reset does not need a host. A feature distinguishes that case with [`feature.hosted`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle-prop-hosted), `true` when a parent or opener window exists, `false` when the document is top-level, known synchronously from the moment [`createFeature`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-createFeature) returns; apps never sniff `window.parent` themselves. `hosted: true` promises a host window, not a host that speaks: connection state stays with `ready()` and the lifecycle events, and unhosted, [`displayMode`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-FeatureHandle-prop-displayMode) stays `null` and `ready()` stays pending.

The reset stylesheet is injected when [`createFeature`](https://www.hyperfrontend.dev/docs/libraries/features/hostee/#api-createFeature) runs, landing after the page's own stylesheet and winning at equal specificity. So paint the feature's background on its root layout element, never on `body`; a `body { background: … }` rule silently loses to the reset. Pass `resetBody: false` to opt out entirely and own the reset yourself.

---

Canonical page: https://www.hyperfrontend.dev/docs/libraries/features/hostee/
This file: https://www.hyperfrontend.dev/docs/libraries/features/hostee.md
Documentation index: https://www.hyperfrontend.dev/llms.txt
