Skip to content

shadcn.io is an independent project built on shadcn/ui

Components

Free

Sandbox Run for React Aria

Code an agent ran in a sandbox, with its status, over tabs for its code, output and files. For React with React Aria, built on Collapsible and Tabs.

An agent's code run shows up as a card: a header line with what ran and a badge, Running, Completed or Error, over tabs for the code, what it printed and the files it wrote.

Use it for a code interpreter's call, where the agent writes a script, runs it in a sandbox and answers from the result. The header is the button that folds the run, so a long one can be put away once it's done; the code tab holds a Code Block, the other tabs whatever the run made. It shows a run and doesn't run anything: to let people edit and run the code, use Sandbox.

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

Anatomy

Sandbox Run anatomy: root, header, tabs list, tabs bar, tab content
SandboxRun
├── SandboxRunHeader (title, state)
└── SandboxRunContent
    └── SandboxRunTabs
        ├── SandboxRunTabsBar
        │   └── SandboxRunTabsList
        │       └── SandboxRunTabsTrigger (one per tab)
        └── SandboxRunTabContent (one per tab)

Usage

import {
  SandboxRun, SandboxRunContent, SandboxRunHeader, SandboxRunTabContent,
  SandboxRunTabs, SandboxRunTabsBar, SandboxRunTabsList,
  SandboxRunTabsTrigger,
} from "@/components/ui/sandbox-run";
<SandboxRun>
  <SandboxRunHeader state="completed" title="Code execution" />
  <SandboxRunContent>
    <SandboxRunTabs defaultValue="code">
      <SandboxRunTabsBar>
        <SandboxRunTabsList>
          <SandboxRunTabsTrigger value="code">Code</SandboxRunTabsTrigger>
          <SandboxRunTabsTrigger value="console">Console</SandboxRunTabsTrigger>
        </SandboxRunTabsList>
      </SandboxRunTabsBar>
      <SandboxRunTabContent value="code">
        <pre className="p-3 font-mono text-xs">console.log(fibonacci(10));</pre>
      </SandboxRunTabContent>
      <SandboxRunTabContent value="console">
        <pre className="p-3 font-mono text-xs">55</pre>
      </SandboxRunTabContent>
    </SandboxRunTabs>
  </SandboxRunContent>
</SandboxRun>

Demos

States

Three runs, closed, one per state: running pulses a dot in a blue badge, completed checks in green and error crosses in red. Each opens on its console, the error's in a destructive Code Block with the traceback. Close a run once it's done when the reply below it matters more, and leave a failed one where the reader can open it.

Set defaultExpanded={false} on SandboxRun to start closed: it starts expanded.

Preview width

Files

Four tabs for one Python run: the code, its output as a table, the console and the files it wrote, with a copy button for the code at the end of SandboxRunTabsBar. Show the tab that answers the question first, here the output, and leave out a tab the run has nothing for: an empty Files tab is a click for nothing.

Preview width

Streaming

Run again prints the console a line at a time, with state at running until the last line and completed after. Stream into the console tab as the sandbox reports, and switch the state only when the run ends, so the badge doesn't say Completed over a console that's still filling.

Preview width

AI SDK

A code run is a tool call, runCode in this example, and SandboxRunHeader takes the tool part's state as it is: the badge reads it the way the table below says. Its input has the code, its output what the run printed.

{message.parts.map((part) =>
  part.type === "tool-runCode" ? (
    <SandboxRun key={part.toolCallId}>
      <SandboxRunHeader state={part.state} title={part.input?.filename} />
      <SandboxRunContent>{/* the tabs, from part.input and part.output */}</SandboxRunContent>
    </SandboxRun>
  ) : null
)}
stateBadge
input-streamingPending
running, input-availableRunning
approval-requestedAwaiting approval
approval-respondedResponded
completed, output-availableCompleted
error, output-errorError
output-deniedDenied

Migrating from AI SDK Elements

If you added Sandbox from AI SDK Elements (opens in a new tab), your project has a components/ai-elements/sandbox.tsx. Here its parts are Sandbox Run's, because Sandbox is the editor that runs code in the page. Run the command in the Installation section, then import from @/components/ui/sandbox-run and rename each part: Sandbox is SandboxRun, SandboxHeader is SandboxRunHeader, SandboxContent is SandboxRunContent, SandboxTabs is SandboxRunTabs, SandboxTabsBar is SandboxRunTabsBar, SandboxTabsList is SandboxRunTabsList, SandboxTabsTrigger is SandboxRunTabsTrigger and SandboxTabContent is SandboxRunTabContent. To leave your JSX as it is, import them under the old names: import { SandboxRun as Sandbox, … }.

The props stay: title and state on the header, which takes a tool part's state as before, and value and defaultValue on the tabs. onValueChange on SandboxRunTabs gets the tab's value.

SandboxRun is a React Aria Disclosure, so it takes defaultExpanded, isExpanded and onExpandedChange where AI Elements' takes defaultOpen, open and onOpenChange.

FAQ

What does installing Sandbox Run add in React?

The sandbox-run file in your ui folder, with the Collapsible, Tabs and Badge it's built from, if you haven't got them. The demos' code tabs use Code Block, which you add on its own. The command uses the shadcn CLI.

What's the difference between Sandbox Run and Sandbox?

Sandbox Run shows code that already ran somewhere else, an agent's sandbox, with what came out of it; nothing runs in the page. Sandbox is an editor with a live preview: the reader changes the code and it runs in an iframe. Their parts are named apart, SandboxRun… and Sandbox…, so one page can use both.

Which states does the header show?

running, completed and error, as a blue badge with a pulsing dot, a green one with a check and a red one with a cross. It also takes an AI SDK tool part's state as it is, input-streaming or output-available, and shows Pending, Awaiting approval, Responded or Denied for the states a run can't name. The dot stops pulsing when the reader asks for reduced motion.

How do I start a run closed?

Set defaultExpanded={false} on SandboxRun: it starts expanded. Hold it yourself with isExpanded and onExpandedChange, to close a run once the reply below it arrives.

Which tabs should a run have?

The ones the run has something for: the code, then what came out, as output, console or files. Name them in SandboxRunTabsTrigger and give each SandboxRunTabContent the same value. SandboxRunTabsBar holds the list and anything after it, a copy or download button, as the Files demo shows.

How do I highlight the code in the code tab?

Put a Code Block in the tab, its lines from the useHighlightedCode hook, as the demos do, with rounded-none border-0 so it sits flush in the run's border. Sandbox Run doesn't highlight anything itself, so a console or an output tab stays plain text.

Can the reader use it with the keyboard?

Yes. The header is a button with aria-expanded: Tab reaches it and Enter or Space opens or closes the run. In the tab list, the arrow keys move between tabs. The chevron sits at the inline end, so it's on the left in a right-to-left page.

API Reference

SandboxRun

PropType
defaultExpanded?boolean

Whether the disclosure is expanded by default (uncontrolled).

Default
true
onExpandedChange?(isExpanded: boolean) → void

Handler that is called when the disclosure expanded state changes.

Parameters

isExpanded – boolean

Returns
void
isExpanded?boolean

Whether the disclosure is expanded (controlled).

className?string

Merged with the part's classes.

SandboxRunContent

PropType
childrenReactNode

The children of the component.

disableAnimation?boolean

Opens and closes it at once, without the height animation.

labelElementType?ElementType

The HTML element used to render the label, e.g. label, or span.

Default
"label"
role?"group" | "region"

The accessibility role for the disclosure's panel.

Type
"group" | "region"
Default
"group"
style?object

The inline [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) for the element.

Type
{ prop?: string]: string | number }
render?DOMRenderFunction<E, T>

Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components. Requirements: - You must render the expected element type (e.g. if <button> is expected, you cannot render an <a>). - Only a single root DOM element can be rendered (no fragments). - You must pass through props and ref to the underlying DOM element, merging with your own prop as appropriate.

Type
DOMRenderFunction<E, T>
className?string

Merged with the part's classes.

SandboxRunHeader

data-slot="sandbox-run-header"

PropType
stateSandboxRunState

Where the run is, shown as a badge after the title.

isDisabled?boolean

Whether the button is disabled.

title?string

What ran, in a few words: "Code execution", "analyze.py".

className?string

Merged with the part's classes.

AttributeType
data-state?string

Mirrors state.

SandboxRunTabContent

data-slot="sandbox-run-tab-content"

PropType
valuestring

The value of the tab that shows it.

children?ChildrenOrFunction<T>

The children of the component. A function may be provided to alter the children based on component state.

Type
ChildrenOrFunction<T>
shouldForceMount?boolean

Whether to mount the tab panel in the DOM even when it is not currently selected. Inactive tab panels are inert and cannot be interacted with. They must be styled appropriately so this is clear to the user visually.

Default
false
style?StyleOrFunction<T>

The inline [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) for the element. A function may be provided to compute the style based on component state.

Type
StyleOrFunction<T>
render?DOMRenderFunction<E, T>

Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components. Requirements: - You must render the expected element type (e.g. if <button> is expected, you cannot render an <a>). - Only a single root DOM element can be rendered (no fragments). - You must pass through props and ref to the underlying DOM element, merging with your own prop as appropriate.

Type
DOMRenderFunction<E, T>
className?string

Merged with the part's classes.

SandboxRunTabs

data-slot="sandbox-run-tabs"

PropType
value?string

The tab shown, controlled.

defaultValue?string

The tab shown first, uncontrolled.

onValueChange?(value: string) → void

Called with the tab chosen.

Parameters

value – string

Returns
void
children?ChildrenOrFunction<T>

The children of the component. A function may be provided to alter the children based on component state.

Type
ChildrenOrFunction<T>
isDisabled?boolean

Whether the TabList is disabled. Shows that a selection exists, but is not available in that circumstance.

keyboardActivation?"automatic" | "manual"

Whether tabs are activated automatically on focus or manually.

Type
"automatic" | "manual"
Default
"automatic"
orientation?"horizontal" | "vertical"

The orientation of the tabs.

Type
"horizontal" | "vertical"
Default
"horizontal"
slot?string | null

A slot name for the component. Slots allow the component to receive props from a parent component. An explicit null value indicates that the local props completely override all props received from a parent.

Type
string | null
Default
sandbox-run-tabs
style?StyleOrFunction<T>

The inline [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) for the element. A function may be provided to compute the style based on component state.

Type
StyleOrFunction<T>
render?DOMRenderFunction<E, T>

Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components. Requirements: - You must render the expected element type (e.g. if <button> is expected, you cannot render an <a>). - Only a single root DOM element can be rendered (no fragments). - You must pass through props and ref to the underlying DOM element, merging with your own prop as appropriate.

Type
DOMRenderFunction<E, T>
className?string

Merged with the part's classes.

SandboxRunTabsBar

<div> data-slot="sandbox-run-tabs-bar"

PropType
className?string

Merged with the part's classes.

SandboxRunTabsList

data-slot="sandbox-run-tabs-list"

PropType
defaultSelectedKey?Key

The initial selected keys in the collection (uncontrolled).

isDisabled?boolean

Whether the TabList is disabled. Shows that a selection exists, but is not available in that circumstance.

onSelectionChange?(key: Key) → void

Handler that is called when the selection changes.

Parameters

key – Key

Returns
void
selectedKey?Key

The currently selected key in the collection (controlled).

variant?"default" | "line"

Ark default: default.

Type
"default" | "line"
Default
"line"
className?string

Merged with the part's classes.

SandboxRunTabsTrigger

data-slot="sandbox-run-tabs-trigger"

PropType
valuestring

The tab's value: the value of the content it shows.

children?ChildrenOrFunction<T>

The children of the component. A function may be provided to alter the children based on component state.

Type
ChildrenOrFunction<T>
isDisabled?boolean

Whether the tab is disabled.

style?StyleOrFunction<T>

The inline [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) for the element. A function may be provided to compute the style based on component state.

Type
StyleOrFunction<T>
render?(props: DetailedHTMLProps<LinkWithRequiredHref, HTMLAnchorElement> | React.JSX.IntrinsicElements[Fallback], renderProps: T) → ReactElement

Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components. Note: You can check if 'href' in props in order to tell whether to render an <a> element. Requirements: - You must render the expected element type (e.g. if <a> is expected, you cannot render a <button>). - Only a single root DOM element can be rendered (no fragments). - You must pass through props and ref to the underlying DOM element, merging with your own prop as appropriate.

Type
(props: DetailedHTMLProps<LinkWithRequiredHref, HTMLAnchorElement> | React.JSX.IntrinsicElements[Fallback], renderProps: T) → ReactElement
Parameters

props – DetailedHTMLProps<LinkWithRequiredHref

HTMLAnchorElement> | React.JSX.IntrinsicElements[Fallback]

renderProps – T

Returns
ReactElement
className?string

Merged with the part's classes.