Browse all components
Code Execution UI
A code interpreter run inside chat — the snippet, a running state, stdout as it streams, and errors that stay readable.
Preview
import json, urllib.request
with urllib.request.urlopen("https://api.example.com/sources") as r:
data = json.load(r)
print(f"collected {len(data["items"])} sources")
print(sorted(s["domain"] for s in data["items"]))Presets
Props
Also takes onStop.
Agent promptClaude Code · Cursor · any agent
Add the Code Execution UI component from the Scrim UI registry to this project and use it in the configuration described below.
Code Execution UI — A code interpreter run inside chat — the snippet, a running state, stdout as it streams, and errors that stay readable.
## 1. Install
```bash
npx shadcn@latest add @scrimui/code-execution
```
This writes a single file to `components/ui/code-execution.tsx`. It is plain React + Tailwind with no runtime dependencies — no Radix, no CVA, nothing to add to package.json. If this project does not use the shadcn CLI, copy the source from https://scrimui.dev/components/code-execution to the same path by hand; nothing in the file depends on shadcn.
## 2. Use it
```tsx
import { CodeExecution } from "@/components/ui/code-execution";
<CodeExecution
code={`import json, urllib.request
with urllib.request.urlopen("https://api.example.com/sources") as r:
data = json.load(r)
print(f"collected {len(data["items"])} sources")
print(sorted(s["domain"] for s in data["items"]))`}
status="running"
exitCode={0}
duration="0.4s"
onStop={() => {}}
/>
```
## 3. The configuration that matters
This is the component's "Running" state — A spinner pill and a Stop control while execution is in flight.
These props were set deliberately and should be preserved as written:
- `status` = "running" — Status
- `output` = "" — stdout
- `duration` = "0.4s" — Duration
Every other prop is at its default; leave those off the call site rather than writing the default value out.
## 4. Wire the handlers
`onStop` is a stub in the snippet above (`() => {}`). Connect it to this project's own state and data layer instead of shipping the empty function.
Reference: https://scrimui.dev/components/code-executionFollows the props below — change a control and the prompt changes with it, so an agent reproduces that configuration instead of the defaults.
Install
npx shadcn@latest add @scrimui/code-executionComponent source
React + Tailwind component using shadcn/ui (badge, button). The install command adds these dependencies automatically.
When copying source manually, install the required primitives first:
npx shadcn@latest add badge button"use client";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import * as React from "react";
/* ------------------------------------------------------------------ */
/* Types */
/* ------------------------------------------------------------------ */
export type CodeExecutionProps = {
code: string;
status?: "running" | "success" | "error";
/** stdout captured so far / on success. */
output?: string;
/** stderr for the error state. */
error?: string;
exitCode?: number;
/** Elapsed time, e.g. "1.2s". */
duration?: string;
onStop?: () => void;
className?: string;
};
/* ------------------------------------------------------------------ */
/* Icons */
/* ------------------------------------------------------------------ */
function TerminalIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" width="14" height="14">
<path d="m4 17 6-6-6-6" />
<path d="M12 19h8" />
</svg>
);
}
function XIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" width="12" height="12">
<path d="M18 6 6 18" />
<path d="m6 6 12 12" />
</svg>
);
}
function CheckIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" width="12" height="12">
<path d="M20 6 9 17l-5-5" />
</svg>
);
}
/* ------------------------------------------------------------------ */
/* CodeExecution */
/* ------------------------------------------------------------------ */
export function CodeExecution({
code,
status = "success",
output,
error,
exitCode = 0,
duration,
onStop,
className = "",
}: CodeExecutionProps) {
const running = status === "running";
const failed = status === "error";
const statusPill = running
? "bg-muted text-muted-foreground"
: failed
? "bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-300"
: "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300";
const statusText = running ? "Running" : failed ? "Failed" : "Succeeded";
return (
<div className={`overflow-hidden rounded-xl border border-border ${className}`}>
<div className="flex items-center gap-2 bg-muted px-3 py-2">
<span className="text-muted-foreground">
<TerminalIcon />
</span>
<span className="text-sm font-medium text-foreground">
Code execution
</span>
{duration && (
<span className="text-xs text-muted-foreground">{duration}</span>
)}
<span className="ml-auto flex items-center gap-2">
{running && onStop && (
<Button variant="outline" size="sm"
type="button"
onClick={onStop}
className="inline-flex h-8 items-center gap-1 rounded-md border border-border px-2 text-xs text-muted-foreground transition-colors hover:bg-muted"
>
<span className="h-2 w-2 rounded-[2px] bg-current" />
Stop
</Button>
)}
<Badge variant="secondary" className={`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium ${statusPill}`}>
{running ? (
<span className="h-2.5 w-2.5 animate-spin rounded-full border-[1.5px] border-current border-t-transparent" />
) : failed ? (
<XIcon />
) : (
<CheckIcon />
)}
{statusText}
</Badge>
</span>
</div>
<pre className="overflow-x-auto bg-muted px-3 py-2.5 text-sm leading-5 text-muted-foreground">
<code>{code}</code>
</pre>
{(output || error) && (
<pre className={`overflow-x-auto px-3 py-2.5 text-xs leading-5 ${failed ? "bg-red-50 text-red-700 dark:bg-red-950/40 dark:text-red-300" : "bg-muted text-muted-foreground"}`}>
{failed ? error : output}
</pre>
)}
{!running && (output || error) && (
<div className={`flex items-center gap-1.5 px-3 pb-2 text-xs ${failed ? "text-red-600 dark:text-red-400" : "text-muted-foreground"}`}>
<span className="font-medium">exit {exitCode}</span>
{duration && ` · ${duration}`}
</div>
)}
</div>
);
}
When to use it
- Show the exact code that ran — trust in an agent's work comes from auditability, not from a summary.
- Render stdout and stderr as real text with a mono font, always scrollable; never truncate silently.
- Keep the Stop control live while running and mark the result as 'stopped' — interruption with retention builds trust.
- Show the exit code and duration; a successful tool call that took 30 seconds is a different signal than one that took 0.3s.
What breaks in production
- Collapsing the code after it runs — the user can't verify what produced the output.
- Rendering output with a normal-width font, making columns and diffs unreadable.
- Hiding a nonzero exit code behind a red pill — the user needs the numbers and the traceback.
Guides
Related Components
How to show a function call in chat — the arguments sent, the result returned, run status, and an expand toggle.
A web search the model ran — the query it chose, how many results came back, and previews of the sources it read.
Render a React component from a tool result instead of text — a skeleton in the widget's own shape, and a text fallback when the client has no renderer.
The result card for AI-generated images, audio and video — queue and stage states, variants, download and regenerate, and a safety block that isn't an error.