Dosu LogoDosu Logo
Ask
Join our Discord
assistant-ui's SpacePublic
assistant-ui
Documentsassistant-ui's Space
primitives
primitives
Type
External
Status
Published
Created
Mar 17, 2026
Updated
Oct 20, 2026
Updated by
Dosu Bot
Source
apps/docs/content/docs/react-native/primitives.mdx

Primitives are thin wrappers around React Native components (View, TextInput, FlatList, Pressable) that integrate with the assistant-ui runtime. They accept all standard React Native props and add runtime-aware behavior.

Primitives are accessed via namespace imports (e.g. ThreadPrimitive.Root, ComposerPrimitive.Input), matching the pattern used in @assistant-ui/react.

Many primitives share their core logic with @assistant-ui/react via @assistant-ui/core/react. Only the UI layer (View/Pressable/Text instead of DOM elements) differs.

Thread#

import { AuiIf, ThreadPrimitive } from "@assistant-ui/react-native";

ThreadPrimitive.Root#

Container View for the thread area.

<ThreadPrimitive.Root style={{ flex: 1 }}>
  {children}
</ThreadPrimitive.Root>
PropTypeDescription
...restViewPropsStandard React Native View props

ThreadPrimitive.Messages#

Deprecated FlatList-based message list kept for backwards compatibility. It uses ThreadPrimitive.MessagesFlatList internally, but keeps the previous no-auto-scroll default so existing apps with custom scroll handling do not change behavior on upgrade.

Use ThreadPrimitive.MessagesFlatList for new React Native threads.

<ThreadPrimitive.Messages>
  {() => <MyMessage />}
</ThreadPrimitive.Messages>

You can also provide role-specific components:

<ThreadPrimitive.Messages>
  {({ message }) => {
    if (message.role === "user") return <MyUserMessage />;
    return <MyAssistantMessage />;
  }}
</ThreadPrimitive.Messages>
PropTypeDescription
children({ message }) => ReactNodeRender function for each message
componentsMessageComponentsDeprecated, use children. Component map: provide either a Message component (used for all roles) or role-specific UserMessage, AssistantMessage, and optionally SystemMessage. Edit composers can be set via EditComposer or role-specific variants (UserEditComposer, AssistantEditComposer, SystemEditComposer).
...restThreadPrimitive.MessagesFlatList propsSame props as ThreadPrimitive.MessagesFlatList, with the auto-scroll options defaulting to false on this deprecated wrapper

ThreadPrimitive.MessagesFlatList#

Canonical React Native message viewport backed by FlatList. It scopes each row to its message, forwards refs to the underlying FlatList, and handles scroll-to-bottom behavior for common chat flows.

<ThreadPrimitive.MessagesFlatList autoScroll>
  {() => <MyMessage />}
</ThreadPrimitive.MessagesFlatList>
PropTypeDescription
children({ message }) => ReactNodeRender function for each message
componentsMessageComponentsDeprecated component map, use children instead
autoScrollbooleanAutomatically keeps the list at the bottom while it is already near the bottom. Defaults to true
scrollToBottomOnRunStartbooleanScrolls to the bottom when a run starts. Defaults to true
scrollToBottomOnInitializebooleanScrolls to the bottom when messages first appear. Defaults to true
scrollToBottomOnThreadSwitchbooleanScrolls to the bottom when switching threads. Defaults to true
history{ hasMore: boolean; isLoadingMore: boolean; loadMore: () => void }Loads older messages when the list reaches its start. See Windowed History
maintainVisibleContentPositionFlatListProps["maintainVisibleContentPosition"]Keeps the first visible message anchored while content is inserted above it, such as older history loading in. Defaults to { minIndexForVisible: 0 }
...restFlatListPropsStandard FlatList props, except data, renderItem, and children

The built-in auto-scroll behavior assumes the default, non-inverted FlatList direction.

ThreadPrimitive.RowsFlatList#

A FlatList over the thread flattened into rows, for long threads where one assistant message holds many parts: a row per user or system message (and per message being edited), per top-level node of an assistant message's part grouping, and per turn end. Each row renders through ThreadPrimitive.Row, so it mounts only that row's scopes, and rows keep stable keys while tokens stream and earlier pages arrive.

import { groupPartByType, ThreadPrimitive } from "@assistant-ui/react-native";

const groupBy = groupPartByType({ reasoning: ["group-reasoning"] });

<ThreadPrimitive.RowsFlatList inverted groupBy={groupBy}>
  {(info) => {
    switch (info.type) {
      case "message":
        if (info.message.composer.isEditing) return <MyEditComposer />;
        return info.message.role === "system" ? (
          <MySystemMessage />
        ) : (
          <MyUserMessage />
        );
      case "part":
        return renderPart(info.part, info.children);
      case "turn-end":
        return <TurnFooter row={info.row} />;
    }
  }}
</ThreadPrimitive.RowsFlatList>;

Keep groupBy at module scope (or in useCallback): a new function on every render rebuilds the row cache and re-renders every row.

PropTypeDescription
children(info) => ReactNodeRender function for each row, with the same contract as ThreadPrimitive.Row
groupBy(part, context) => readonly `group-${string}`[] | nullCoalesces adjacent assistant parts into one row, like MessagePrimitive.GroupedParts; without it every part is its own row. Keep its identity stable
invertedbooleanRenders the newest row at offset 0. Earlier pages load through onEndReached, and maintainVisibleContentPosition defaults to { minIndexForVisible: 0, autoscrollToTopThreshold: 4 } (without the threshold when autoScroll is false), so the visible row stays put while rows arrive and the list follows new rows while it is at the bottom. A list header at least 1pt tall, empty unless you pass ListHeaderComponent, keeps the list anchored on a newest row that renders nothing, such as a turn-end footer hidden while the reply streams
autoScroll, scrollToBottomOnRunStart, scrollToBottomOnInitialize, scrollToBottomOnThreadSwitchbooleanAs on ThreadPrimitive.MessagesFlatList; with inverted, the bottom is offset 0
history{ hasMore: boolean; isLoadingMore: boolean; loadMore: () => void }As on ThreadPrimitive.MessagesFlatList: defaults to the runtime's thread.hasEarlier paging, and loads at the start of the list, or at its end when inverted
...restFlatListPropsStandard FlatList props, except data, renderItem, keyExtractor, and children

Without inverted, it keeps the first visible row anchored with { minIndexForVisible: 0 }, exactly as ThreadPrimitive.MessagesFlatList does for messages.

ThreadPrimitive.MessageByIndex#

Renders a single message at a specific index in the thread. Provides message context so that useAuiState((s) => s.message) works inside the rendered component. This component is shared from @assistant-ui/core/react.

<ThreadPrimitive.MessageByIndex
  index={0}
  components={{
    UserMessage: MyUserMessage,
    AssistantMessage: MyAssistantMessage,
  }}
/>
PropTypeDescription
indexnumberZero-based index of the message to render
componentsMessageComponentsSame component map as ThreadPrimitive.Messages

ThreadPrimitive.Empty#

Renders its children only when the thread is empty (no messages and not loading). Deprecated in favor of AuiIf.

<ThreadPrimitive.Empty>
  <Text>Send a message to get started</Text>
</ThreadPrimitive.Empty>

// preferred
<AuiIf condition={(s) => s.thread.isEmpty}>
  <Text>Send a message to get started</Text>
</AuiIf>

ThreadPrimitive.If#

Conditional rendering based on thread state. Deprecated in favor of AuiIf.

<ThreadPrimitive.If empty>
  <Text>No messages yet</Text>
</ThreadPrimitive.If>

// preferred
<AuiIf condition={(s) => s.thread.isEmpty}>
  <Text>No messages yet</Text>
</AuiIf>

<AuiIf condition={(s) => s.thread.isRunning}>
  <ActivityIndicator />
</AuiIf>
PropTypeDescription
emptybooleanRenders children when thread emptiness matches this value
runningbooleanRenders children when thread running state matches this value

ThreadPrimitive.Suggestion#

Pressable that inserts or sends a hard-coded suggestion prompt. Unlike SuggestionPrimitive.Trigger, this component does not require a suggestion context. The prompt is passed directly as a prop.

<ThreadPrimitive.Suggestion prompt="What can you help me with?" send>
  <Text>What can you help me with?</Text>
</ThreadPrimitive.Suggestion>
PropTypeDescription
promptstringThe text to send or insert into the composer
sendbooleanWhen true, sends the prompt immediately; when false, inserts into composer (default: false)
clearComposerbooleanWhether to replace composer text (default: true)
...restPressablePropsStandard Pressable props (except onPress)

ThreadPrimitive.Suggestions#

Renders all suggestions through a children render function. This component is shared from @assistant-ui/core/react.

<ThreadPrimitive.Suggestions>
  {() => <MySuggestion />}
</ThreadPrimitive.Suggestions>
PropTypeDescription
children(value: { suggestion: SuggestionState }) => ReactNodeRender function called for each suggestion
components{ Suggestion: ComponentType }Deprecated, use children. Component to render for each suggestion

ThreadPrimitive.SuggestionByIndex#

Renders a single suggestion at the specified index, providing suggestion context. This component is shared from @assistant-ui/core/react.

<ThreadPrimitive.SuggestionByIndex
  index={0}
  components={{ Suggestion: MySuggestion }}
/>
PropTypeDescription
indexnumberZero-based index of the suggestion to render
components{ Suggestion: ComponentType }Component to render for the suggestion

AuiIf#

Conditional rendering based on assistant state. Replaces the deprecated ThreadPrimitive.Empty, ThreadPrimitive.If, MessagePrimitive.If, and ComposerPrimitive.If.

import { AuiIf } from "@assistant-ui/react-native";

<AuiIf condition={(s) => s.thread.isEmpty}>
  <Text>Send a message to get started</Text>
</AuiIf>

<AuiIf condition={(s) => s.thread.isRunning}>
  <ActivityIndicator />
</AuiIf>
PropTypeDescription
condition(state) => booleanSelector that determines whether children are rendered

Composer#

import {
  ComposerPrimitive,
  QueueItemPrimitive,
} from "@assistant-ui/react-native";

Using your own button#

Every pressable primitive accepts asChild, including the action bar, branch picker, attachment, queue item, suggestion, thread list, thread list item, and chain of thought triggers, as well as the composer controls. With it, the primitive renders its single child instead of its own Pressable and passes its press handler, disabled state, and accessibility role to that child, so a button from your UI kit becomes the press target.

<ComposerPrimitive.Send asChild>
  <Button>
    <Text>Send</Text>
  </Button>
</ComposerPrimitive.Send>

The child's onPress runs before the primitive's action, the child's other props take precedence, styles are combined (including Pressable style functions), and refs are composed. The child must forward these props to a pressable element.

ComposerPrimitive.Root#

Container View for the composer area.

<ComposerPrimitive.Root style={styles.composerContainer}>
  {children}
</ComposerPrimitive.Root>

ComposerPrimitive.Input#

TextInput wired to the composer runtime. Value and onChangeText are managed automatically.

<ComposerPrimitive.Input
  placeholder="Message..."
  multiline
  style={styles.input}
/>
PropTypeDescription
submitMode"enter" | "none"Whether Enter sends the message on web (default: "enter")
...restTextInputPropsStandard TextInput props (except value, onChangeText)

ComposerPrimitive.Send#

Pressable that sends the current message. Automatically disabled when the composer is empty.

<ComposerPrimitive.Send style={styles.sendButton}>
  <Text>Send</Text>
</ComposerPrimitive.Send>

ComposerPrimitive.Cancel#

Pressable that cancels the current run. Automatically disabled when no run is active.

<ComposerPrimitive.Cancel style={styles.cancelButton}>
  <Text>Stop</Text>
</ComposerPrimitive.Cancel>

ComposerPrimitive.Attachments#

Renders composer attachments through a children render function.

<ComposerPrimitive.Attachments>
  {({ attachment }) => {
    if (attachment.type === "image") return <MyImageAttachment />;
    if (attachment.type === "document") return <MyDocumentAttachment />;
    return <MyFallbackAttachment />;
  }}
</ComposerPrimitive.Attachments>
PropTypeDescription
children(value: { attachment: Attachment }) => ReactNodeRender function called for each attachment
components{ Image?, Document?, File?, Attachment? }Deprecated, use children. Component renderers by attachment type

ComposerPrimitive.AddAttachment#

Pressable for adding attachments. It is disabled while the composer cannot accept attachments. React Native has no file input, so the caller opens the platform picker (for example expo-document-picker or expo-image-picker) in onPress and passes the selection to aui.composer.addAttachment.

import { useAui } from "@assistant-ui/react-native";
import * as ImagePicker from "expo-image-picker";
import { Text } from "react-native";

const aui = useAui();

<ComposerPrimitive.AddAttachment
  onPress={async () => {
    const result = await ImagePicker.launchImageLibraryAsync({ base64: true });
    if (result.canceled) return;
    for (const asset of result.assets) {
      if (!asset.base64 || !asset.mimeType) continue;
      await aui.composer.addAttachment({
        name: asset.fileName ?? `image.${asset.mimeType.split("/")[1]}`,
        contentType: asset.mimeType,
        type: "image",
        content: [
          {
            type: "image",
            image: `data:${asset.mimeType};base64,${asset.base64}`,
          },
        ],
      });
    }
  }}
  <Text>Attach</Text>
</ComposerPrimitive.AddAttachment>

ComposerPrimitive.Queue#

Renders all queued composer items. Each item is wrapped in a QueueItemByIndexProvider, so QueueItemPrimitive.* can read item state and call queue actions inside the render prop. Backed by the shared ComposerPrimitiveQueue from @assistant-ui/core/react.

<ComposerPrimitive.Queue>
  {({ queueItem }) => (
    <View>
      <QueueItemPrimitive.Text />
      <QueueItemPrimitive.Steer>
        <Text>Run now</Text>
      </QueueItemPrimitive.Steer>
      <QueueItemPrimitive.Remove>
        <Text>Remove</Text>
      </QueueItemPrimitive.Remove>
    </View>
  )}
</ComposerPrimitive.Queue>
PropTypeDescription
children(value: { queueItem: QueueItemState }) => ReactNodeRender function called for each queue item

ComposerPrimitive.Quote#

Renders the active composer quote preview. Children are only rendered while s.composer.quote is set, so this acts as both a container and a gate.

<ComposerPrimitive.Quote>
  <View>
    <Text>Quoting:</Text>
    <ComposerPrimitive.QuoteText />
    <ComposerPrimitive.QuoteDismiss>
      <Text>Clear</Text>
    </ComposerPrimitive.QuoteDismiss>
  </View>
</ComposerPrimitive.Quote>
PropTypeDescription
childrenReactNodeQuote preview content; only rendered when a quote is set
...restViewPropsStandard React Native View props

ComposerPrimitive.QuoteText#

Renders the quoted text from s.composer.quote?.text. Pass children to override the displayed value.

<ComposerPrimitive.QuoteText />
PropTypeDescription
childrenReactNodeOverride content; defaults to s.composer.quote?.text
...restTextPropsStandard React Native Text props

ComposerPrimitive.QuoteDismiss#

Pressable that clears the active quote by calling aui.composer.setQuote(undefined).

<ComposerPrimitive.QuoteDismiss>
  <Text>Clear</Text>
</ComposerPrimitive.QuoteDismiss>
PropTypeDescription
childrenPressableProps["children"]Button content, including Pressable render-function children
...restOmit<PressableProps, "onPress">Standard React Native Pressable props except onPress

ComposerPrimitive.AttachmentByIndex#

Renders a single composer attachment at the specified index. Useful for building custom attachment layouts.

<ComposerPrimitive.AttachmentByIndex
  index={0}
  components={{
    Image: MyImageAttachment,
    Attachment: MyFallbackAttachment,
  }}
/>
PropTypeDescription
indexnumberZero-based index of the attachment to render
components{ Image?, Document?, File?, Attachment? }Component renderers by attachment type

Editing a message#

There are no separate edit primitives. Inside a message, the composer primitives bind to that message's edit composer, so the same ComposerPrimitive.Root, Input, Send, and Cancel build the edit UI. ActionBarPrimitive.Edit starts editing, and message.composer.isEditing tells you when to render it.

import { Text, View } from "react-native";
import {
  ComposerPrimitive,
  MessagePrimitive,
  useAuiState,
} from "@assistant-ui/react-native";

function MessageRow() {
  const isEditing = useAuiState((s) => s.message.composer.isEditing);
  if (isEditing) return <EditComposer />;
  return <MessageBubble />;
}

function EditComposer() {
  return (
    <MessagePrimitive.Root>
      <ComposerPrimitive.Root style={styles.editComposer}>
        <ComposerPrimitive.Input multiline autoFocus style={styles.input} />
        <View style={styles.editActions}>
          <ComposerPrimitive.Cancel style={styles.cancelButton}>
            <Text>Cancel</Text>
          </ComposerPrimitive.Cancel>
          <ComposerPrimitive.Send style={styles.sendButton}>
            <Text>Update</Text>
          </ComposerPrimitive.Send>
        </View>
      </ComposerPrimitive.Root>
    </MessagePrimitive.Root>
  );
}

Conditional Rendering (Composer)#

Use AuiIf for conditional rendering based on composer state:

<AuiIf condition={(s) => s.composer.isEditing}>
  <Text>Currently editing</Text>
</AuiIf>

<AuiIf condition={(s) => s.composer.dictation != null}>
  <Text>Dictation active</Text>
</AuiIf>

Message#

import { MessagePrimitive } from "@assistant-ui/react-native";

MessagePrimitive.Root#

Container View for a single message.

<MessagePrimitive.Root style={styles.messageBubble}>
  {children}
</MessagePrimitive.Root>

MessagePrimitive.Content#

Renders message content parts using render-prop functions instead of the component-map approach used by MessagePrimitive.Parts. Each part type receives a part object and its index. Registered toolkit renderers are automatically dispatched and take priority over renderToolCall.

<MessagePrimitive.Content
  renderText={({ part }) => <Text>{part.text}</Text>}
  renderToolCall={({ part, index }) => (
    <Text>Tool: {part.toolName}</Text>
  )}
  renderImage={({ part }) => (
    <Image source={{ uri: part.image }} />
  )}
/>
PropTypeDescription
renderText(props: { part, index }) => ReactElementRenderer for text parts (default: React Native <Text>)
renderToolCall(props: { part, index }) => ReactElementFallback renderer for tool-call parts not handled by registered tool UIs
renderImage(props: { part, index }) => ReactElementRenderer for image parts (default: React Native <Image>)
renderReasoning(props: { part, index }) => ReactElementRenderer for reasoning parts
renderSource(props: { part, index }) => ReactElementRenderer for source parts
renderFile(props: { part, index }) => ReactElementRenderer for file parts
renderData(props: { part, index }) => ReactElementFallback renderer for data parts not handled by registered data UIs

Rendering Markdown#

MessagePrimitive.Content renders text parts with React Native's <Text> by default, so markdown syntax is displayed as plain text. To render markdown, install a React Native markdown renderer and pass it through renderText:

<InstallCommand npm={["react-native-markdown-display"]} />

import Markdown from "react-native-markdown-display";
import { MessagePrimitive } from "@assistant-ui/react-native";

const AssistantMessage = () => {
  return (
    <MessagePrimitive.Root>
      <MessagePrimitive.Content
        renderText={({ part }) => (
          <Markdown>{part.text}</Markdown>
        )}
      />
    </MessagePrimitive.Root>
  );
};

MessagePrimitive.Parts#

Renders message content parts through a children render function or a components map. Tool call and data parts automatically render registered toolkit renderers and data UIs (via useAssistantDataUI), falling back to components provided here. A default Text component using React Native's <Text> is provided out of the box.

<MessagePrimitive.Parts>
  {({ part }) => {
    if (part.type === "text") return <Text>{part.text}</Text>;
    if (part.type === "image") return <Image source={{ uri: part.image }} />;
    if (part.type === "tool-call") return <MyToolCallComponent {...part} />;
    return null;
  }}
</MessagePrimitive.Parts>
PropTypeDescription
children(value: { part: EnrichedPartState }) => ReactNodeRender function called for each part. Cannot be combined with components
componentsobjectComponent map for rendering each part type. See below.

components fields:

FieldTypeDescription
TextTextMessagePartComponentText part renderer (default: React Native <Text>)
ImageImageMessagePartComponentImage part renderer
ReasoningReasoningMessagePartComponentReasoning part renderer
SourceSourceMessagePartComponentSource part renderer
FileFileMessagePartComponentFile part renderer
Unstable_AudioUnstable_AudioMessagePartComponentAudio part renderer (deprecated, render audio/* from File)
tools{ by_name?, Fallback? } or { Override }Tool call rendering config. Use by_name to map tool names to components, Fallback for unregistered tools, or Override to handle all tool calls
data{ by_name?, Fallback? }Data part rendering config. Use by_name to map data event names, Fallback for unmatched events
EmptyEmptyMessagePartComponentComponent shown for empty messages
QuoteQuoteMessagePartComponentComponent for rendering quoted message references
ChainOfThoughtComponentTypeGroups all reasoning and tool-call parts into a single component (mutually exclusive with Reasoning/tools/ToolGroup/ReasoningGroup)

MessagePrimitive.PartByIndex#

Renders a single message part at the specified index, providing part context. Useful for building custom part layouts outside of MessagePrimitive.Parts. This component is shared from @assistant-ui/core/react.

<MessagePrimitive.PartByIndex
  index={0}
  components={{
    Text: ({ text }) => <Text>{text}</Text>,
    tools: { Fallback: MyToolComponent },
  }}
/>
PropTypeDescription
indexnumberZero-based index of the message part to render
componentsobjectSame component map as MessagePrimitive.Parts

MessagePrimitive.Quote#

Renders the quote a message was sent with, read from s.message.metadata.custom.quote. Renders nothing when the message carries no quote. Place it above MessagePrimitive.Parts in the user message. This component is shared from @assistant-ui/core/react.

<MessagePrimitive.Quote>
  {({ text }) => <Text numberOfLines={2}>{text}</Text>}
</MessagePrimitive.Quote>
PropTypeDescription
children(value: { text: string; messageId: string }) => ReactNodeRender function called when the message has a quote

Conditional Rendering (Message)#

Use AuiIf for conditional rendering based on message properties:

<AuiIf condition={(s) => s.message.role === "user"}>
  <Text>You said:</Text>
</AuiIf>

<AuiIf condition={(s) => s.message.role === "assistant" && s.message.isLast}>
  <ActivityIndicator />
</AuiIf>

MessagePrimitive.Attachments#

Renders user message attachments through a children render function.

<MessagePrimitive.Attachments>
  {({ attachment }) => {
    if (attachment.type === "image") return <MyImageAttachment />;
    return <MyFallbackAttachment />;
  }}
</MessagePrimitive.Attachments>
PropTypeDescription
children(value: { attachment: Attachment }) => ReactNodeRender function called for each attachment
components{ Image?, Document?, File?, Attachment? }Deprecated, use children. Component renderers by attachment type

MessagePrimitive.AttachmentByIndex#

Renders a single message attachment at the specified index. Useful for building custom attachment layouts outside of MessagePrimitive.Attachments.

<MessagePrimitive.AttachmentByIndex
  index={0}
  components={{
    Image: MyImageAttachment,
    Attachment: MyFallbackAttachment,
  }}
/>
PropTypeDescription
indexnumberZero-based index of the attachment to render
components{ Image?, Document?, File?, Attachment? }Component renderers by attachment type

Attachment#

import { AttachmentPrimitive } from "@assistant-ui/react-native";

Primitives for rendering individual attachments (inside ComposerPrimitive.Attachments or MessagePrimitive.Attachments).

AttachmentPrimitive.Root#

Container View for an attachment.

<AttachmentPrimitive.Root style={styles.attachment}>
  {children}
</AttachmentPrimitive.Root>

AttachmentPrimitive.Name#

Text component displaying the attachment filename.

<AttachmentPrimitive.Name style={styles.filename} />

AttachmentPrimitive.Thumb#

Text component displaying the file extension (e.g. .pdf), or the attachment type (e.g. image) when the filename has no extension (including leading-dot names like .env). If you pass children, they override that text.

<AttachmentPrimitive.Thumb style={styles.extension} />

AttachmentPrimitive.Remove#

Pressable that removes the attachment from the composer.

<AttachmentPrimitive.Remove>
  <Text>Remove</Text>
</AttachmentPrimitive.Remove>

QueueItem#

import { QueueItemPrimitive } from "@assistant-ui/react-native";

Primitives for rendering individual queued composer items. Use inside a ComposerPrimitive.Queue render prop, where the queue item context is set up by QueueItemByIndexProvider.

QueueItemPrimitive.Text#

Renders the queue item's text with React Native <Text>. Pass children to override the displayed value.

<QueueItemPrimitive.Text />
PropTypeDescription
childrenReactNodeOverride content; defaults to the text parts of s.queueItem.parts
...restTextPropsStandard React Native Text props

QueueItemPrimitive.Remove#

Pressable that removes the queue item by calling aui.queueItem.remove().

<QueueItemPrimitive.Remove>
  <Text>Remove</Text>
</QueueItemPrimitive.Remove>
PropTypeDescription
childrenPressableProps["children"]Button content, including Pressable render-function children
...restOmit<PressableProps, "onPress">Standard React Native Pressable props except onPress

QueueItemPrimitive.Steer#

Pressable that promotes the queue item to run next by calling aui.queueItem.steer().

<QueueItemPrimitive.Steer>
  <Text>Run now</Text>
</QueueItemPrimitive.Steer>
PropTypeDescription
childrenPressableProps["children"]Button content, including Pressable render-function children
...restOmit<PressableProps, "onPress">Standard React Native Pressable props except onPress

ActionBar#

import { ActionBarPrimitive } from "@assistant-ui/react-native";

ActionBarPrimitive.Copy#

Pressable that copies the message content. Pass a platform clipboard writer through copyToClipboard. Supports function-as-children for copy state feedback.

import * as Clipboard from "expo-clipboard";

const copyToClipboard = async (text: string) => {
  const didCopy = await Clipboard.setStringAsync(text);
  if (!didCopy) throw new Error("Clipboard write failed");
};

<ActionBarPrimitive.Copy
  copiedDuration={3000}
  copyToClipboard={copyToClipboard}
  {({ isCopied }) => <Text>{isCopied ? "Copied!" : "Copy"}</Text>}
</ActionBarPrimitive.Copy>
PropTypeDescription
copiedDurationnumberDuration in ms to show "copied" state (default: 3000)
copyToClipboard(text: string) => void | Promise<void>Platform clipboard writer

ActionBarPrimitive.Edit#

Pressable that enters edit mode for a message.

<ActionBarPrimitive.Edit>
  <Text>Edit</Text>
</ActionBarPrimitive.Edit>

ActionBarPrimitive.Reload#

Pressable that regenerates an assistant message.

<ActionBarPrimitive.Reload>
  <Text>Retry</Text>
</ActionBarPrimitive.Reload>

ActionBarPrimitive.FeedbackPositive / ActionBarPrimitive.FeedbackNegative#

Pressable buttons for submitting message feedback. The submitted one is marked for assistive technology: aria-selected on native, aria-pressed on the web.

<ActionBarPrimitive.FeedbackPositive>
  {({ isSubmitted }) => <Text>{isSubmitted ? "Liked" : "Like"}</Text>}
</ActionBarPrimitive.FeedbackPositive>

<ActionBarPrimitive.FeedbackNegative>
  {({ isSubmitted }) => <Text>{isSubmitted ? "Disliked" : "Dislike"}</Text>}
</ActionBarPrimitive.FeedbackNegative>

BranchPicker#

import { BranchPickerPrimitive } from "@assistant-ui/react-native";

BranchPickerPrimitive.Previous / BranchPickerPrimitive.Next#

Pressable buttons to navigate between message branches.

<View style={{ flexDirection: "row", alignItems: "center" }}>
  <BranchPickerPrimitive.Previous>
    <Text>-</Text>
  </BranchPickerPrimitive.Previous>
  <BranchPickerPrimitive.Number />
  <Text>/</Text>
  <BranchPickerPrimitive.Count />
  <BranchPickerPrimitive.Next>
    <Text>+</Text>
  </BranchPickerPrimitive.Next>
</View>

BranchPickerPrimitive.Number / BranchPickerPrimitive.Count#

Text components displaying the current branch number and total count.

ThreadList#

import { ThreadListPrimitive } from "@assistant-ui/react-native";

ThreadListPrimitive.Root#

Container View for the thread list.

<ThreadListPrimitive.Root style={styles.threadList}>
  {children}
</ThreadListPrimitive.Root>

ThreadListPrimitive.Items#

FlatList of thread IDs with runtime integration.

<ThreadListPrimitive.Items
  renderItem={({ threadId }) => (
    <ThreadListEntry threadId={threadId} />
  )}
/>
PropTypeDescription
renderItem(props: { threadId: string; index: number }) => ReactElementThread item renderer
...restFlatListPropsStandard FlatList props (except data, renderItem)

ThreadListPrimitive.New#

Pressable that creates a new thread. While the new thread is the current one, it is marked for assistive technology: accessibilityState.selected on native, aria-current on the web.

<ThreadListPrimitive.New style={styles.newThreadButton}>
  <Text>New Chat</Text>
</ThreadListPrimitive.New>

ThreadListItem#

import { ThreadListItemPrimitive } from "@assistant-ui/react-native";

Primitives for rendering individual thread list items.

ThreadListItemPrimitive.Root#

Container View for a thread list item.

<ThreadListItemPrimitive.Root style={styles.threadItem}>
  {children}
</ThreadListItemPrimitive.Root>

ThreadListItemPrimitive.Title#

Renders the thread title text. Falls back to the provided fallback when title is empty. This component is shared from @assistant-ui/core/react.

<ThreadListItemPrimitive.Title fallback="New Chat" />
PropTypeDescription
fallbackReactNodeContent to show when title is empty

ThreadListItemPrimitive.Trigger#

Pressable that switches to the thread. The current thread's trigger is marked for assistive technology: accessibilityState.selected on native, aria-current on the web.

<ThreadListItemPrimitive.Trigger>
  <ThreadListItemPrimitive.Title fallback="New Chat" />
</ThreadListItemPrimitive.Trigger>

ThreadListItemPrimitive.Delete#

Pressable that deletes the thread.

<ThreadListItemPrimitive.Delete>
  <Text>Delete</Text>
</ThreadListItemPrimitive.Delete>

ThreadListItemPrimitive.Archive / ThreadListItemPrimitive.Unarchive#

Pressable buttons that archive or unarchive the thread.

<ThreadListItemPrimitive.Archive>
  <Text>Archive</Text>
</ThreadListItemPrimitive.Archive>

<ThreadListItemPrimitive.Unarchive>
  <Text>Unarchive</Text>
</ThreadListItemPrimitive.Unarchive>

Suggestion#

import { SuggestionPrimitive } from "@assistant-ui/react-native";

Primitives for rendering suggestions. Use inside ThreadPrimitive.Suggestions or a SuggestionByIndexProvider.

SuggestionPrimitive.Title#

Text component displaying the suggestion title.

<SuggestionPrimitive.Title style={styles.suggestionTitle} />

SuggestionPrimitive.Description#

Text component displaying the suggestion description/label.

<SuggestionPrimitive.Description style={styles.suggestionDescription} />

SuggestionPrimitive.Trigger#

Pressable that triggers the suggestion action (send or insert into composer).

<SuggestionPrimitive.Trigger send>
  <SuggestionPrimitive.Title />
</SuggestionPrimitive.Trigger>
PropTypeDescription
sendbooleanWhen true, sends immediately; when false, inserts into composer
clearComposerbooleanWhether to clear/replace composer text (default: true)

ChainOfThought#

import { ChainOfThoughtPrimitive } from "@assistant-ui/react-native";

Primitives for rendering chain of thought content (grouped reasoning and tool-call parts).

ChainOfThoughtPrimitive.Root#

Container View for chain of thought content.

<ChainOfThoughtPrimitive.Root style={styles.chainOfThought}>
  {children}
</ChainOfThoughtPrimitive.Root>

ChainOfThoughtPrimitive.AccordionTrigger#

Pressable that toggles the collapsed state of the chain of thought.

<ChainOfThoughtPrimitive.AccordionTrigger>
  <Text>Toggle reasoning</Text>
</ChainOfThoughtPrimitive.AccordionTrigger>

ChainOfThoughtPrimitive.Parts#

Renders the parts within a chain of thought. Shared from @assistant-ui/core/react.

<ChainOfThoughtPrimitive.Parts>
  {({ part }) => {
    if (part.type === "reasoning") return <Text>{part.text}</Text>;
    if (part.type === "tool-call") return <MyToolComponent {...part} />;
    return null;
  }}
</ChainOfThoughtPrimitive.Parts>
Documents
AG-UI Message History Management
CHANGELOG
CHANGELOG
CHANGELOG
external-store
overview
README
AG-UI Streaming State Management
hooks
index
introduction
overview
part-1
README
README
stockbroker
AI SDK Integration
ai-sdk
assistant-runtime-provider
expo
hooks
index
index
index
introduction
migration
migration
overview
part-2
README
README
README
README
README
README
README
README
stockbroker
Cloud Message Pagination
index
Generative UI Date and Time Controls
In-Memory Thread Lifecycle
CHANGELOG
CHANGELOG
CHANGELOG
Local Runtime Message History
CHANGELOG
Markdown Preprocessing and Repair
CHANGELOG
CHANGELOG
MCP App Tool UI Rendering
CHANGELOG
CHANGELOG
message
MCP OAuth State Management
MessageRepository Branch Pointer Invariant
Next.js Cache Components
Remote Thread List Runtime
adapters
CHANGELOG
CHANGELOG
hooks
index
README
README
thread-runtime
Render Prop Leakage
Run Cancellation and Abort Signal Propagation
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
README
Run Telemetry Model ID Extraction
SSR-Safe Thread ID Generation
Stream Decoder Buffer Limits
CHANGELOG
CHANGELOG
StreamdownTextPrimitive
index
Streaming Markdown Rendering
CHANGELOG
CHANGELOG
index
introduction
part-1
AGENTS
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CODE_OF_CONDUCT
CONTRIBUTING
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README_LANGGRAPH
SECURITY
SPEC
SPEC_AssistantFrame
SPEC_ModelContextRegistry
action-bar
action-bar-more
adapters
artifacts
assistant-if
assistant-modal
assistant-modal
assistant-runtime
assistant-sidebar
attachment
attachment
attachment-runtime
branch-picker
chatgpt
claude
composer
composer-runtime
composition
context-display
custom-backend
custom-backend
error
file
form-demo
grok
heat-graph
hooks
image
index
index
index
index
index
index
index
index
index
markdown
mem0
mermaid
message-part
message-part-runtime
message-runtime
message-timing
modal
model-selector
part-3
perplexity
pick-a-runtime
primitives
primitives
quote
reasoning
selection-toolbar
sources
suggestion
syntax-highlighting
thread
thread
thread-list
thread-list
thread-list-item
thread-list-item-more
thread-list-item-runtime
thread-list-runtime
tool-fallback
tool-group
tw-shimmer
v4-legacy
v5-legacy