Documents
primitives
primitives
Type
External
Status
Published
Created
Mar 17, 2026
Updated
Mar 17, 2026

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 vs DOM elements) differs.

Thread#

import { 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#

FlatList-based message list with automatic runtime integration. Each message is wrapped in a scoped context so that useAuiState((s) => s.message) works inside the rendered component.

<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
componentsMessageComponentsComponent 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).
...restFlatListPropsStandard FlatList props (except data, renderItem)

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 has no messages. Deprecated in favor of AuiIf.

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

ThreadPrimitive.If#

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

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

<ThreadPrimitive.If running>
  <ActivityIndicator />
</ThreadPrimitive.If>
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 using the provided component configuration. This component is shared from @assistant-ui/core/react.

<ThreadPrimitive.Suggestions>
  {() => <MySuggestion />}
</ThreadPrimitive.Suggestions>
PropTypeDescription
components{ Suggestion: ComponentType }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 } from "@assistant-ui/react-native";

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 using the provided component configuration.

<ComposerPrimitive.Attachments>
  {({ attachment }) => {
    if (attachment.type === "image") return <MyImageAttachment />;
    if (attachment.type === "document") return <MyDocumentAttachment />;
    return <MyFallbackAttachment />;
  }}
</ComposerPrimitive.Attachments>
PropTypeDescription
components{ Image?, Document?, File?, Attachment? }Component renderers by attachment type

ComposerPrimitive.AddAttachment#

Pressable for triggering attachment addition. The actual file picker must be implemented by the consumer (e.g. using expo-document-picker or expo-image-picker).

<ComposerPrimitive.AddAttachment>
  <Text>Attach</Text>
</ComposerPrimitive.AddAttachment>

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

ComposerPrimitive.EditInput#

TextInput wired to the edit composer runtime. Used inside an edit composer to allow editing an existing message. Value and onChangeText are managed automatically.

<ComposerPrimitive.EditInput
  placeholder="Edit message..."
  multiline
  style={styles.input}
/>
PropTypeDescription
...restTextInputPropsStandard TextInput props (except value, onChangeText)

ComposerPrimitive.EditSend#

Pressable that confirms and submits a message edit. Automatically disabled when the composer is empty.

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

ComposerPrimitive.EditCancel#

Pressable that cancels an in-progress message edit and returns to the original message.

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

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 tool UIs (via useAssistantTool) 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
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

MessagePrimitive.Parts#

Renders message content parts via a components prop. Tool call and data parts automatically render registered tool UIs (via useAssistantTool / 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
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_AudioAudioMessagePartComponentAudio part renderer (experimental)
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

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 using the provided component configuration.

<MessagePrimitive.Attachments>
  {({ attachment }) => {
    if (attachment.type === "image") return <MyImageAttachment />;
    return <MyFallbackAttachment />;
  }}
</MessagePrimitive.Attachments>
PropTypeDescription
components{ Image?, Document?, File?, Attachment? }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).

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

AttachmentPrimitive.Remove#

Pressable that removes the attachment from the composer.

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

ActionBar#

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

ActionBarPrimitive.Copy#

Pressable that copies the message content. Supports function-as-children for copy state feedback.

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

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.

<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.

<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.

<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 a SuggestionByIndexProvider (from @assistant-ui/core/react).

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>