Let the model compose cards, tables, charts, and form controls drawn with React Native components.
The model can answer with an interface built from the generative UI vocabulary: cards, text, tables, charts, form controls, and more, the same components Generative UI documents for the web. On React Native, Metro resolves @assistant-ui/generative-ui/spec to a React Native build through the react-native export condition, so toSpecCatalog draws every component with React Native's own components and no other dependency. createSpecToolkit from generative-frame/spec/assistant-ui resolves the same way and renders the model's render_spec calls in your thread.
Install
npx expo install @assistant-ui/generative-ui generative-frame zod@assistant-ui/generative-ui takes react-native as an optional peer, and generative-frame also takes @assistant-ui/react-native; your app already has both.
Add it to your runtime
The toolkit runs render_spec in the app, so its entries go into Tools({ toolkit }), and the toolkit's spec module carries the guidance the model needs to write specs for this catalog:
import {
AuiConfig,
AssistantRuntimeProvider,
Tools,
useAssistantInstructions,
type AssistantRuntime,
} from "@assistant-ui/react-native";
import { toSpecCatalog } from "@assistant-ui/generative-ui/spec";
import { createSpecToolkit } from "generative-frame/spec/assistant-ui";
import { Thread } from "@/components/assistant-ui/elements/thread.aui";
const { catalog, components } = toSpecCatalog();
const spec = createSpecToolkit(catalog, { components });
const tools = Tools({
toolkit: spec.entries({ execution: "frontend", display: "standalone" }),
});
const guidance = (spec.modules ?? [])
.map((module) => module.guidance())
.join("\n\n");
function SpecInstructions() {
useAssistantInstructions(guidance);
return null;
}
export function RuntimeProvider({ runtime }: { runtime: AssistantRuntime }) {
const config = AuiConfig({ tools });
return (
<AssistantRuntimeProvider runtime={runtime} config={config}>
<SpecInstructions />
<Thread />
</AssistantRuntimeProvider>
);
}Your route forwards the toolkit's tools to the model, as for any frontend tool. To run render_spec on the server instead, see frontend and backend execution.
On a phone
Every component dispatches the same events with the same payloads as on the web, writes a value bound with $bindState back the same way, and an asForm Card or a Form collects its named controls when a submit button or a field's return key submits it. The default styles follow the device's light or dark mode, and text on a Card with its own background turns white.
A few components take a form that suits a touch screen:
SelectandRadioGroupare single-choice lists, andCheckboxGroupis a list of checkboxes.Slideris a stepper with buttons on either side of its value.DatePickeris a text field with a format hint.Chartdraws every chart kind as bars.Iconis a text character.Carouselpages through its cards in a horizontal scroll view.backgroundtakes a color React Native can paint, and a CSS gradient leaves the plain surface. ABoxtakes points, pixels, rems, or percentages.
Change a component
defaultGenerativeUILibrary from @assistant-ui/generative-ui/spec is the React Native vocabulary. Replace an entry to restyle a component, or add your own, as on the web:
import { Text } from "react-native";
import { z } from "zod";
import {
defaultGenerativeUILibrary,
toSpecCatalog,
} from "@assistant-ui/generative-ui/spec";
export const { catalog, components } = toSpecCatalog({
...defaultGenerativeUILibrary,
Rating: {
description: "A rating from 1 to 5 stars.",
properties: z.object({ value: z.number().int().min(1).max(5) }),
render: ({ value }) => <Text>{"★".repeat(value)}</Text>,
},
});