Appearance
Safe-area-inset CSS variables
The platform exposes four CSS variables on every iframe's :root:
| Variable | Default | Notes |
|---|---|---|
--poe-safe-area-inset-top | env(safe-area-inset-top) | Notch / status bar clearance |
--poe-safe-area-inset-bottom | env(safe-area-inset-bottom) | Home indicator clearance |
--poe-safe-area-inset-left | env(safe-area-inset-left) | Landscape rounded-corner clearance (left) |
--poe-safe-area-inset-right | env(safe-area-inset-right) | Landscape rounded-corner clearance (right) |
Use these in place of raw env(safe-area-inset-*) whenever you pad against the viewport edge. The kernel injects the defaults automatically. When the parent app overlays UI on top of the iframe (e.g. a top bar, bottom tab bar, split-view divider), it overrides the relevant variables so the child does not double-pad behind the parent's chrome.
Consuming the variables
Always include an env(...) fallback for non-platform hosts (third-party embedders, dev servers):
css
.bottom-bar {
padding-bottom: var(
--poe-safe-area-inset-bottom,
env(safe-area-inset-bottom)
);
}
.top-header {
padding-top: var(--poe-safe-area-inset-top, env(safe-area-inset-top));
}
/* Inside a tailwind arbitrary value */
class="bottom-[calc(1rem+var(--poe-safe-area-inset-bottom,env(safe-area-inset-bottom)))]"Wrap with max(..., 0px) only when you already wrapped the bare env(...) value that way — var(...) may evaluate to a negative computed value in pathological browser bugs and max(.., 0px) guards against that. Most apps just need the bare var(...).
Declaring overrides for a child app
If your app nests another app via <poe-app> and draws chrome on top of its iframe, declare the corresponding insets so the child does not pad behind your chrome.
html
<!-- Initial value at mount: pass as JSON in an HTML attribute -->
<poe-app
type-id="chat"
instance-id="123"
safe-area-insets='{"top":48,"bottom":56}'
></poe-app>ts
// Update at runtime via the JS property — beats the HTML attribute.
const el = document.querySelector<HTMLElement>("poe-app")!;
(el as any).safeAreaInsets = { top: 48, bottom: 56 };
// Or use the convenience setter exported from the SDK:
import { setChildSafeAreaInsets } from "poe-apps-sdk/v1/client.js";
setChildSafeAreaInsets(el, { top: 48, bottom: 56 });
// Clear the override (child resumes device env() defaults):
setChildSafeAreaInsets(el, null);Each side is a CSS px length (number). Sides omitted from the object fall through to the device env(safe-area-inset-<side>) default — partial overrides are supported. Values are validated at the platform boundary: non-finite, negative, or values above 2000px are dropped.
Runtime updates are applied without remounting the child iframe — they flow as a poe:safe-area-insets postMessage to the child's contentWindow, which the child SDK applies inline. Use this for chrome that changes during the session (sidebar open/close, keyboard transitions, orientation flips).
What not to do
- ❌
padding-bottom: env(safe-area-inset-bottom);— ignores parent-app overlays. - ❌ Setting per-side
0and the others omitted to "force" no inset — omitted sides already fall through to the device default. Set0only when you specifically want to override that side to zero. - ❌ Posting
poe:safe-area-insetsmessages directly from app code — use the<poe-app>setter orsetChildSafeAreaInsets. The element knows which iframecontentWindowto target.