inline-cards - interactive shtml code blocks in chat messages
SYNOPSIS
Use ```shtml fenced code blocks in chat messages to render interactive cards inline. The HTML content is hydrated into a sandboxed iframe after your response completes. Cards are ephemeral — they have a minimal bridge (lick-only) and no persistent state.
RENDERING
Inline cards render AFTER your response completes — not during streaming. The message renderer preserves ```shtml blocks as raw HTML, then hydrateInlineSprinkles() finds all code.language-shtml elements and replaces each with a sandboxed iframe.
Auto-height is handled via ResizeObserver. The iframe automatically resizes to fit its content — no manual height setting needed.
In CLI mode the content renders as a direct srcdoc iframe. In extension mode it routes through sprinkle-sandbox.html (a CSP-exempt manifest sandbox) which creates a nested srcdoc iframe inside it.
BRIDGE API
Inline cards have a minimal bridge. Only slicc.lick() is available. There is NO readFile, NO setState/getState, NO on('update'). This is unlike panel sprinkles which have the full bridge API.
// Send a lick event with action string only
slicc.lick('approve')
// Send a lick event with action + data
slicc.lick({action: 'deploy', data: {env: 'production', version: '2.1'}})
The data-action attribute is also supported. Any element with data-action automatically calls slicc.lick() on click:
<button data-action="approve">Approve</button>
<button data-action="reject" data-action-data='{"reason":"stale"}'>Reject</button>
LICK EVENT ROUTING
Lick events from inline cards arrive as messages in the agent's conversation. They are routed to the cone as sprinkle lick events with sprinkleName: "inline". The message content is formatted as:
[Sprinkle Event: inline]
```json
{"action": "deploy", "data": {"env": "production"}}
```
These are fire-and-forget — the agent does NOT block waiting for the user to click. The lick arrives as an asynchronous message in the cone's conversation.
WHEN TO USE INLINE CARDS
- Choices — present options for the user to pick from
- Confirmations — "Deploy to prod?" with Confirm/Cancel buttons
- Progress updates — show status with action buttons
- Quick actions — one-click triggers for common operations
WHEN TO USE ALTERNATIVES
- Panel sprinkles (
sprinkle open) — for dashboards, reports, editors, and persistent UIs that need the full bridge (readFile, setState, on('update')). - Sprinkle chat (
sprinkle chat '<html>') — for blocking user input needed mid-tool-execution. The command blocks until the user clicks, then returns the action as JSON to stdout. Use this when you need a response before continuing.
CSS COMPONENTS
Theme CSS and sprinkle component styles are auto-injected into the iframe. Use the built-in classes — do not write custom CSS.
.sprinkle-action-card— card with header, body, and actions row. Children:__header,__body,__actions(all optional)..sprinkle-btn— button. Variants:--primary(accent fill),--secondary(outline),--negative(red),--quiet(no border)..sprinkle-badge— solid-fill badge. Variants:--positive,--negative,--notice,--informative..sprinkle-btn-group— horizontal button group with gap.
EXAMPLE
Action card with deploy/cancel buttons:
```shtml
<div class="sprinkle-action-card">
<div class="sprinkle-action-card__header">
Deploy to Production
<span class="sprinkle-badge sprinkle-badge--notice">pending</span>
</div>
<div class="sprinkle-action-card__body">
Version 2.1.0 is ready. 14 files changed, all tests passing.
</div>
<div class="sprinkle-action-card__actions">
<button class="sprinkle-btn sprinkle-btn--secondary"
onclick="slicc.lick('cancel')">Cancel</button>
<button class="sprinkle-btn sprinkle-btn--primary"
onclick="slicc.lick({action:'deploy',data:{env:'prod'}})">Deploy</button>
</div>
</div>
```
SEE ALSO
shtml(1), sprinkle(1), lick(1)