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

import { ThreadSample } from "@/components/docs/samples/thread";

A complete chat interface that combines message rendering, auto-scrolling, composer input,
attachments, and conditional UI states. Fully customizable and composable.

Anatomy#

The Thread component is built with the following primitives:

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

<ThreadPrimitive.Root>
  <ThreadPrimitive.Viewport>
    <AuiIf condition={(s) => s.thread.isEmpty}>
      <ThreadWelcome />
      {/* ThreadWelcome includes ThreadPrimitive.Suggestions */}
    </AuiIf>

    <ThreadPrimitive.Messages>
      {({ message }) => {
        if (message.role === "user") return <UserMessage />;
        return <AssistantMessage />;
      }}
    </ThreadPrimitive.Messages>

    <ThreadPrimitive.ViewportFooter>
      <ThreadPrimitive.ScrollToBottom />
      <Composer />
    </ThreadPrimitive.ViewportFooter>
  </ThreadPrimitive.Viewport>
</ThreadPrimitive.Root>

Getting Started#

Add the component#

<InstallCommand shadcn={["thread"]} />

This adds a /components/assistant-ui/thread.tsx file to your project, which you can adjust as needed.

Use in your application#

import { Thread } from "@/components/assistant-ui/thread";

export default function Chat() {
  return (
    <div className="h-full">
      <Thread />
    </div>
  );
}

Examples#

Welcome Screen#

<AuiIf condition={(s) => s.thread.isEmpty}>
  <ThreadWelcome />
</AuiIf>

Viewport Spacer#

<AuiIf condition={(s) => !s.thread.isEmpty}>
  <div className="min-h-8 grow" />
</AuiIf>

Conditional Send/Cancel Button#

<AuiIf condition={(s) => !s.thread.isRunning}>
  <ComposerPrimitive.Send>
    Send
  </ComposerPrimitive.Send>
</AuiIf>

<AuiIf condition={(s) => s.thread.isRunning}>
  <ComposerPrimitive.Cancel>
    Cancel
  </ComposerPrimitive.Cancel>
</AuiIf>

Suggestions#

Display suggested prompts using the Suggestions API. See the Suggestions guide for detailed configuration.

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

// Configure suggestions in your runtime provider
const aui = useAui({
  suggestions: Suggestions(["What's the weather?", "Tell me a joke"]),
});

// Display suggestions in your thread component
<ThreadPrimitive.Suggestions>
  {() => <SuggestionItem />}
</ThreadPrimitive.Suggestions>

// Custom suggestion item
const SuggestionItem = () => (
  <SuggestionPrimitive.Trigger send asChild>
    <button>
      <SuggestionPrimitive.Title />
    </button>
  </SuggestionPrimitive.Trigger>
);

API Reference#

The following primitives are used within the Thread component and can be customized in your /components/assistant-ui/thread.tsx file.

Root#

Contains all parts of the thread.

<ParametersTable
type="ThreadPrimitiveRootProps"
parameters={[
{
name: "asChild",
type: "boolean",
default: "false",
description: "Merge props with child element instead of rendering a wrapper div.",
},
{
name: "className",
type: "string",
description: "CSS class name.",
},
]}
/>

This primitive renders a <div> element unless asChild is set.

Viewport#

The scrollable area containing all messages. Automatically scrolls to the bottom as new messages are added.

<ParametersTable
type="ThreadPrimitiveViewportProps"
parameters={[
{
name: "asChild",
type: "boolean",
default: "false",
description: "Merge props with child element instead of rendering a wrapper div.",
},
{
name: "autoScroll",
type: "boolean",
default: "true",
description:
"Whether to automatically scroll to the bottom when new messages are added while the viewport was previously scrolled to the bottom.",
},
{
name: "className",
type: "string",
description: "CSS class name.",
},
]}
/>

This primitive renders a <div> element unless asChild is set.

Messages#

Renders all messages in the thread. This primitive renders a separate component for each message.

<ThreadPrimitive.Messages>
  {({ message }) => {
    if (message.role === "user") return <UserMessage />;
    return <AssistantMessage />;
  }}
</ThreadPrimitive.Messages>

<ParametersTable
type="ThreadPrimitiveMessagesProps"
parameters={[
{
name: "components",
type: "MessageComponents",
required: true,
description: "Components to render for different message types.",
children: [
{
type: "MessageComponents",
parameters: [
{
name: "Message",
type: "ComponentType",
description: "Default component for all messages.",
},
{
name: "UserMessage",
type: "ComponentType",
description: "Component for user messages.",
},
{
name: "EditComposer",
type: "ComponentType",
description:
"Component for user messages being edited.",
},
{
name: "AssistantMessage",
type: "ComponentType",
description: "Component for assistant messages.",
},
{
name: "SystemMessage",
type: "ComponentType",
description: "Component for system messages.",
},
],
},
],
},
]}
/>

MessageByIndex#

Renders a single message at the specified index.

<ThreadPrimitive.MessageByIndex
  index={0}
  components={{
    UserMessage: UserMessage,
    AssistantMessage: AssistantMessage
  }}
/>

<ParametersTable
type="ThreadPrimitiveMessageByIndexProps"
parameters={[
{
name: "index",
type: "number",
required: true,
description: "The index of the message to render.",
},
{
name: "components",
type: "MessageComponents",
description: "Components to render for different message types.",
},
]}
/>

Empty#

Renders children only when there are no messages in the thread.

<ParametersTable
type="ThreadPrimitiveEmptyProps"
parameters={[
{
name: "children",
type: "ReactNode",
description: "Content to display when the thread is empty.",
},
]}
/>

ScrollToBottom#

A button to scroll the viewport to the bottom. Disabled when the viewport is already at the bottom.

<ParametersTable
type="ThreadPrimitiveScrollToBottomProps"
parameters={[
{
name: "asChild",
type: "boolean",
default: "false",
description: "Merge props with child element instead of rendering a wrapper button.",
},
{
name: "className",
type: "string",
description: "CSS class name.",
},
]}
/>

This primitive renders a <button> element unless asChild is set.

Suggestions#

Renders all configured suggestions. Configure suggestions using the Suggestions() API in your runtime provider.

<ThreadPrimitive.Suggestions>
  {() => <CustomSuggestionComponent />}
</ThreadPrimitive.Suggestions>

<ParametersTable
type="ThreadPrimitiveSuggestionsProps"
parameters={[
{
name: "components",
type: "{ Suggestion: ComponentType }",
description: "Custom component to render each suggestion.",
},
]}
/>

See the [Suggestions guide](/docs/guides/suggestions) for detailed information on configuring and customizing suggestions.

AuiIf#

Conditionally renders children based on assistant state. This is a generic component that can access thread, message, composer, and other state.

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

<AuiIf condition={(s) => s.thread.isEmpty}>
  <WelcomeScreen />
</AuiIf>

<AuiIf condition={(s) => s.thread.isRunning}>
  <LoadingIndicator />
</AuiIf>

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

<ParametersTable
type="AuiIfProps"
parameters={[
{
name: "condition",
type: "(state: AssistantState) => boolean",
required: true,
description: "A function that receives the assistant state and returns whether to render children.",
},
]}
/>

The condition function receives an `AssistantState` object with access to `thread`, `message`, `composer`, `part`, and `attachment` state depending on context.