Skip to content
Neon UI
Esc
navigateopen⌘Jpreview
On this page

PreviewFrame

Sandbox iframe with wake, restart, and refresh lifecycle.

PreviewFrame is the workspace’s window into the running app: a sandboxed iframe in quiet chrome — a status dot, a mono URL readout, and refresh / restart / open-in-new-tab actions. The chrome never moves; lifecycle states play out as overlays. While the sandbox wakes, the NeonLoader resolves out of grain over a scrim; on error, a structured panel offers a restart. When the agent finishes an edit, bump reloadSignal and the frame remounts without any chrome motion.

acme-crm.vibe.app

Install

npx shadcn@latest add https://ui.neon.com/r/preview-frame.json

Usage

import { PreviewFrame } from "@/components/neon-ui/preview-frame";

<PreviewFrame
  className="h-96"
  src="https://sandbox-8f2k.internal.dev"
  displaySrc="https://acme-crm.vibe.app"
  title="Live app preview"
  state={sandbox.state}
  reloadSignal={editCount}
  onRestart={() => restartSandbox()}
/>;

States

  • Ready — the app full bleed; the header dot holds primary.
  • Refresh — the built-in refresh remounts the iframe and the glyph turns once (500ms ease-out), so the click reads even when the reload is instant.
  • Sleeping — the app dims behind a scrim with a moon, mono sleeping, and a detail line; the dot rests dim. A click anywhere on the frame (or the wake action) calls onWake.
  • Waking — a scrim covers the app with the NeonLoader and one mono line; the dot breathes muted. Use it for cold starts, wakes, and post-restart polling.
  • Error — the scrim holds with a mono error prefix, an optional detail line, and a restart action; the dot cools to destructive.
  • Reload on signal — increment reloadSignal from outside (e.g. after each agent edit) to remount the frame with zero chrome motion.

Every overlay is absolute — the frame never changes height. The restart button’s hover tells you what it’s about to do: destructive while the sandbox is running, primary when it’s down.

Props

PropType
srcstring

The sandbox URL the frame renders.

Typestring
titlestring

Accessible name for the iframe.

Typestring
displaySrc?string

What the header readout shows when the real src is an internal sandbox host.

Typestring
Defaultsrc
state?"ready" | "sleeping" | "waking" | "error"

Lifecycle state; everything but ready renders as an overlay.

Type"ready" | "sleeping" | "waking" | "error"
Default"ready"
onWake?() => void

Renders the wake action in the sleeping state; the whole scrim is click-to-wake.

Type() => void
sleepingDetail?string

One line under the sleeping title.

Typestring
Default"Compute suspended after inactivity."
reloadSignal?number

Bump to force a reload from outside, e.g. after the agent applies an edit.

Typenumber
Default0
onRestart?() => void

Renders the restart action in the header and the error panel.

Type() => void
onRefresh?() => void

Notified after the built-in refresh reloads the frame.

Type() => void
errorDetail?string

One line of detail under the error title.

Typestring
wakingLabel?string

Copy under the loader while waking.

Typestring
Default"Waking sandbox"
actions?ReactNode

Extra actions rendered before the built-in header buttons.

TypeReactNode
sandbox?string

The iframe sandbox policy.

Typestring
Default"allow-scripts allow-same-origin allow-forms"

Accessibility

  • The iframe carries the required title; header actions are labelled icon buttons.
  • The error overlay is role="alert" so the failure is announced.
  • The waking loader exposes status text through NeonLoader’s role="status".
  • The refresh spin and overlay fades are static under prefers-reduced-motion.