# @copilotkit/channels-ui
A pure **JSX runtime + intermediate representation (IR) + cross-platform
component vocabulary** for authoring rich bot messages. No React, no agent
runtime, no Slack — `@copilotkit/channels-ui` depends on nothing in the repo
except `@copilotkit/shared` (for `StandardSchemaV1` types). That's what lets
a platform adapter (e.g. `@copilotkit/channels-slack`) translate the same UI into
Block Kit, while keeping the component layer tree-shakeable and testable in
isolation.
You author UI as JSX, it normalizes to one serializable IR (`BotNode[]`), and
behavior props (`onClick` / `onSelect` / `onSubmit`) ride along on the nodes
for the engine (`@copilotkit/channels`) to bind.
## Install
```sh
pnpm add @copilotkit/channels-ui
```
To author components as JSX, point the TypeScript JSX factory at this package
in the consuming project's `tsconfig.json`:
```jsonc
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@copilotkit/channels-ui",
},
}
```
This package ships `@copilotkit/channels-ui/jsx-runtime` (and
`/jsx-dev-runtime`) exporting `jsx` / `jsxs` / `Fragment`. Author component
files as `.tsx`.
## Example
```tsx
import {
Message,
Header,
Section,
Actions,
Button,
renderToIR,
} from "@copilotkit/channels-ui";
function Greeting({ name }: { name: string }) {
return (
Hello {name}Pick an option — **bold** and `code` work too.
);
}
const ir = renderToIR();
// ir is BotNode[] — hand it to an adapter, or let @copilotkit/channels post it.
```
`renderToIR(ui: Renderable): BotNode[]` recursively invokes any component
function (passing its props) until only intrinsic string-typed nodes remain;
strings in children become `{ type: "text", props: { value } }`; `Fragment`
flattens its children. Components must be **pure functions of serializable
props** — same props in, same tree out — which is what makes content-stable
action binding and re-render rehydration possible in `@copilotkit/channels`.
`Renderable` also accepts a `{ raw }` escape hatch, which `renderToIR` passes
through as `{ type: "raw", props: { value } }` for adapters that want to
short-circuit to a native payload.
## Component vocabulary
Each component is a thin function returning a `BotNode` with a stable
intrinsic `type` string. An adapter maps these to native primitives.
Every component has a fully-typed prop interface (`MessageProps`,
`ButtonProps`, …, all exported), and the package ships its own `JSX` namespace
(resolved via `jsxImportSource: "@copilotkit/channels-ui"`). So JSX is statically
checked: unknown attributes, wrong prop values, and bad children are
compile-time errors — `` or `