> ## Documentation Index
> Fetch the complete documentation index at: https://docs.metabind.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Native rendering

> How a single BindJS definition becomes React on the web, SwiftUI on iOS, and Jetpack Compose on Android

Every Interactive Tool in an MCP App is written once in BindJS and compiles to three rendering targets:

* **React** in MCP hosts (Claude Desktop, ChatGPT, VS Code, Cursor) via `@metabindai/bindjs-react`, inside a sandboxed iframe.
* **SwiftUI** on iOS, macOS, and visionOS via the `BindJS` library from [bindjs-apple](https://github.com/metabindai/bindjs-apple), when embedded in your own app via the Assistant SDK.
* **Jetpack Compose** on Android via [bindjs-android](https://github.com/metabindai/bindjs-android), when embedded via the Assistant SDK.

The same component definition reaches every surface. Same governance, same brand, same behavior. The renderer changes; the component does not.

<Frame>
  <img src="https://mintcdn.com/yapstudios/AbHCU8qlH_Ners-2/images/diagrams/native-rendering-platforms.svg?fit=max&auto=format&n=AbHCU8qlH_Ners-2&q=85&s=2f6b77534d0d779fbbbedae351ad3837" alt="A single BindJS layout component renders as SwiftUI on iOS via bindjs-apple, as Jetpack Compose on Android via bindjs-android, and as React on the web via @metabindai/bindjs-react." noZoom width="960" height="540" data-path="images/diagrams/native-rendering-platforms.svg" />
</Frame>

## Why this works

BindJS is the open component language for agent UI, with a SwiftUI-inspired API. A component author writes layout, behavior, and styling using primitives like `VStack`, `HStack`, `Text`, `Image`, `frame`, `padding`, and `foregroundStyle`. These primitives have a well-defined semantic meaning, and each renderer maps them to the platform's native equivalent:

| BindJS primitive | React | SwiftUI | Jetpack Compose |
| - | - | - | - |
| `VStack`, `HStack`, `ZStack` | flex containers | `VStack`, `HStack`, `ZStack` | `Column`, `Row`, `Box` |
| `Text` | `<span>` with applied styles | `Text` | `Text` |
| `Image` | `<img>` | `Image` | `AsyncImage` / `Image` |
| `Button` | `<button>` | `Button` | `Button` |
| `frame`, `padding`, `cornerRadius` | CSS rules | view modifiers | `Modifier` chain |
| Gestures (`onTapGesture`, etc.) | event handlers | `gesture` modifiers | `pointerInput` |

Because each renderer targets the platform's own UI toolkit, the mobile output isn't a web view in disguise — it's real SwiftUI and real Jetpack Compose, with 60 FPS scrolling, native gestures, and platform conventions. On the web, the output is React components in the DOM.

## Two rendering paths

<Frame>
  <img src="https://mintcdn.com/yapstudios/AbHCU8qlH_Ners-2/images/diagrams/two-rendering-paths.svg?fit=max&auto=format&n=AbHCU8qlH_Ners-2&q=85&s=2fe3e00554407f8f7452ee8603de7e2b" alt="A single BindJS component compiles to one bundle and reaches two paths: MCP hosts (sandboxed iframe + @metabindai/bindjs-react) and Assistant SDK (SwiftUI / Compose / React inside your app)." noZoom width="960" height="620" data-path="images/diagrams/two-rendering-paths.svg" />
</Frame>

Both paths receive the same compiled bundle from the Metabind server. The difference is what's on the other side of the renderer interface.

## What's compiled and what's runtime

Components are compiled to a portable BindJS bundle on the server when a Type is published or when a tool call resolves. The bundle is a content-addressed package containing:

* The compiled `body` function for each component.
* Asset references resolved to CDN URLs.
* Dependency packages (other projects' components your project imports).

The bundle is delivered to the renderer, which executes the body function with the validated input. Rendering happens in the renderer's process — there is no JavaScript executing on the host MCP server during a render.

For Data Tools, the equivalent compilation produces a JavaScript bundle that runs in a V8 sandbox on the Metabind server (not in the renderer). See [Tools and Types](/guides/concepts/types).

## What's available and where

Every rendering target is open source under Apache 2.0. The BindJS runtime and React renderer — `@metabindai/bindjs-runtime` and `@metabindai/bindjs-react`, from the [bindjs-runtime](https://github.com/metabindai/bindjs-runtime) repo — power what Claude, ChatGPT, and every other MCP host show your users. The SwiftUI engine ([bindjs-apple](https://github.com/metabindai/bindjs-apple), covering iOS, macOS, and visionOS) and the Jetpack Compose engine ([bindjs-android](https://github.com/metabindai/bindjs-android)) render the same components when embedded in your own app via the Assistant SDK.

Your tool definitions, schemas, and components are exportable; the protocol path on the wire is open MCP. The hosted platform — Metabind Studio, the hosted MCP App Server, and the agent proxy — is the commercial product.

## Performance characteristics

* **Edge-cached bundles.** Compiled component bundles are content-addressed by hash and pushed to global CDN edges. The first request to a render path is one round trip; subsequent requests hit the cache.
* **No cold starts on the render path.** The renderer is preloaded in the host or SDK; rendering a tool result is bundle parse + body execution.
* **Native gestures and animations.** On iOS and Android, rendering is platform-native, so scroll velocity, gesture recognition, and animation timing match the rest of the embedding app.

## When the rendering target matters for the component author

Most BindJS components compile cleanly across all three targets without special-casing. There are a few areas where the renderer's capabilities differ:

* **Custom drawing.** Canvas-based components, WebGL, or `Shader` components have a primary target and may render as a static fallback on others.
* **Platform-specific gestures.** A SwiftUI-only gesture pattern can be expressed in BindJS, but it'll behave differently on Compose and React.
* **3D models.** USDZ on iOS, GLB on Android and web. The platform picks the right format from the asset's `model` references.

Where target-specific behavior matters, BindJS provides surfaces for declaring it; otherwise the platform handles the mapping.

## What to read next

<CardGroup cols={2}>
  <Card title="Components and Packages" icon="cube" href="/guides/concepts/components">
    The unit that gets compiled to each rendering target.
  </Card>

  <Card title="MCP Apps integration" icon="grid" href="/guides/connecting-to-mcp-hosts/claude-desktop">
    How rendering works inside Claude Desktop and other MCP hosts.
  </Card>

  <Card title="Assistant SDK" icon="mobile" href="/guides/getting-started/embed-an-assistant">
    Native rendering inside your own iOS, Android, or web app.
  </Card>

  <Card title="BindJS Reference" icon="book" href="/bindjs/introduction">
    Component primitives, modifiers, and property system.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.