Skip to content
Back to skills

Inline Embeds

ASecurity

How to render interactive previews of app screens inline in agent chat via sandboxed iframes. Covers the `embed` fence syntax, the `postNavigate` pop-out helper, and when to prefer an embed over prose / a static image.

  • 6,969 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 27, 2026
data-aishellreactsecurity

Works with

  • cli

Security analysis

A100/100

Scanned May 27, 2026

npx -y skills add BuilderIO/agent-native --skill inline-embeds --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Inline Embeds?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Inline Embeds
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/builderio-inline-embeds/badge)](https://www.skillsdirectory.com/skills/builderio-inline-embeds)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: inline-embeds
description: >-
  How to render interactive previews of app screens inline in agent chat via
  sandboxed iframes. Covers the `embed` fence syntax, the `postNavigate` pop-out
  helper, and when to prefer an embed over prose / a static image.
---

# Inline Embeds

The chat renderer lets you embed a sandboxed iframe pointing at any same-origin
route of this app, rendered inline with your reply. Use this when a live,
interactive preview communicates more than prose or a static screenshot — a
chart, an email thread, a slide, a form, a ticket.

## The `embed` fence

Emit a fenced code block with the language `embed`:

````
```embed
src: /email?id=msg_123
aspect: 4/3
title: Re: Q4 planning
```
````

Keys:

| Key      | Required | Notes                                                              |
| -------- | -------- | ------------------------------------------------------------------ |
| `src`    | yes      | Same-origin path beginning with `/`. Cross-origin URLs are blocked |
| `aspect` | no       | `16/9` (default), `4/3`, `3/2`, `2/1`, `21/9`, `1/1`               |
| `title`  | no       | Accessible label + hover tooltip                                   |
| `height` | no       | Fixed pixel height when aspect ratio doesn't fit                   |

The rendered iframe is sandboxed (`allow-scripts allow-same-origin allow-forms
allow-popups`) and `referrerpolicy="same-origin"`. The browser enforces that
the iframe can't navigate the parent window.

## When to reach for an embed

- A chart or visualization that benefits from tooltips / hover.
- A detail view the user might want to scan (email, ticket, event, slide).
- Anything where "here's a link to it" would force an extra click.

**Don't** embed when plain prose, a bulleted list, or a small table is enough.
**Don't** embed external sites — the renderer blocks cross-origin URLs.

## "Open in main window" button — `postNavigate`

Every embed route should include a small "Open" button so the user can pop the
view out of the chat and into the full app. Import the helper from
`@agent-native/core/client`:

```tsx
import { postNavigate, isInAgentEmbed } from "@agent-native/core/client";

export function OpenButton({ path }: { path: string }) {
  if (!isInAgentEmbed()) return null;
  return (
    <button onClick={() => postNavigate(path)}>Open</button>
  );
}
```

`postNavigate` sends a `postMessage` to the parent chat window. The chat
renderer validates the message is same-origin, same-iframe, and the path is
relative, then updates the parent URL via `history.pushState` so react-router
navigates without a page reload.

When the page is loaded directly (not in an iframe), `postNavigate` falls back
to a same-window navigation, so the button works both ways.

## Adding an embed route to a template

1. Create a chromeless route (e.g. `app/routes/email.tsx`) that renders the
   detail view without the app shell.
2. Mark the route path as bare in `app/components/layout/Layout.tsx` so the
   sidebar / header don't render inside the iframe.
3. Render the existing detail component with a transparent background so it
   blends into the chat theme.
4. Include an `<OpenButton>` that calls `postNavigate("/path/to/detail")`.
5. Document the embed URL in this template's `AGENTS.md` so the agent knows
   what's embeddable.

The framework-level fence renderer and security enforcement apply
automatically — no per-template wiring beyond the route and layout bypass.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…