BindJS is Metabind’s declarative cross-platform UI framework. You write a component once in a SwiftUI-inspired component language, and it renders as React on the web, SwiftUI on iOS, and Jetpack Compose on Android — without web views, and without per-platform forks. It’s the language MCP App Studio uses to author Interactive Tools. Those tools render inside MCP hosts like Claude Desktop, ChatGPT, and VS Code, and they render natively when embedded in your own iOS, Android, or web app via the Metabind Assistant SDK. The component definition is the same on every surface.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.
Why BindJS
A growing class of applications needs to render server-defined or model-generated UI on multiple platforms. Interactive UI returned from MCP tool calls is one example. LLM-generated component output that ships into a mobile app is another. Most existing approaches in this space assume the renderer is a web view, so the UI ends up looking like a website wherever it appears. BindJS takes a different position. A UI definition should be one declarative document that the host renders natively — as SwiftUI on iOS, Jetpack Compose on Android, or React on the web — rather than a web view embedded everywhere. The samedefineComponent source produces native, 60 FPS UI on all three targets, with native gestures, native animations, and native typography. Authors stay in one source file; users get the platform their device runs on.
The four pieces
A conforming BindJS implementation has four parts:- Runtime — a small JavaScript runtime that executes component code, manages state, and emits a JSON AST describing the UI tree.
- AST and component catalog — the wire format that the runtime emits, plus the catalog of component and modifier names a renderer must understand (
Text,VStack,padding,onTapGesture, and so on). - Renderers — per-platform implementations that walk the AST and produce native views: React, SwiftUI, and Jetpack Compose.
- Modifier pipeline — the chained styling and behavior modifiers (
.padding(),.foregroundStyle(),.onTapGesture()) applied in order before the renderer paints the underlying view.
A first look
A BindJS component packages abody render function and an optional properties schema into a defineComponent call exported as the module default. Properties are declared with helper functions like PropertyString and PropertyBoolean, and the body’s props argument is typed against the schema with no manual interface needed.
props is fully typed — props.title is string, props.showAction is boolean — inferred from the property schema. Second, layout and styling use function calls and method chaining instead of JSX. VStack, Text, and Button are functions that return components; modifiers like .font() and .foregroundStyle() chain off them.
Where BindJS runs
BindJS components compile to a single bundle that reaches multiple rendering targets. Each target is a different renderer reading the same AST.| Surface | Renderer | Platform |
|---|---|---|
| MCP hosts (Claude Desktop, ChatGPT, VS Code, Cursor) | @bindjs/renderer in a sandboxed iframe | React on the web |
| Assistant SDK embedded in your iOS app | BindJSRuntime | SwiftUI on iOS, macOS, and visionOS |
| Assistant SDK embedded in your Android app | BindJS runtime | Jetpack Compose |
| Assistant SDK embedded in your web app | @bindjs/renderer | React |
VStack becomes a SwiftUI VStack on iOS, a Compose Column on Android, and a flex container on the web. Same governance, same brand, same behavior; the renderer changes, the component does not. See native rendering for the full mapping.
Authoring primitives
BindJS files declare one of two primitives, each exported as the module’s default.defineComponent is the canonical case. It packages a body, an optional properties schema, and optional metadata, previews, thumbnail, and icon fields into a single component definition. Almost every component you write — buttons, cards, lists, layouts — is a defineComponent call.
defineButtonStyle is the sibling primitive for custom button styles. It takes a body that receives a configuration (with the button’s label and isPressed) and optional props, and is applied to a Button via the .buttonStyle() modifier. Use it when you want a reusable button appearance you can attach to any button in your project.
metabind.d.ts, the canonical TypeScript declaration file the runtime ships.
What to read next
Quickstart
Build your first BindJS component in five steps.
Authoring components
The
defineComponent shape, metadata, body, and previews in depth.MCP host integration
How a BindJS component becomes an Interactive Tool inside an MCP host.
Layout — Stacks
A reference page for
VStack, HStack, ZStack, and the lazy variants.