Reasoning

Collapsible UI for displaying AI reasoning and thinking messages.

Outline (default)
Ghost
Muted

Getting Started

Add reasoning

npx shadcn@latest add https://r.assistant-ui.com/reasoning.json

This adds a /components/assistant-ui/reasoning.tsx file to your project.

Use in your application

Pass the Reasoning and ReasoningGroup components to the MessagePrimitive.Parts component:

/app/components/assistant-ui/thread.tsx
import { MessagePrimitive } from "@assistant-ui/react";
import { Reasoning, ReasoningGroup } from "@/components/assistant-ui/reasoning";

const AssistantMessage: FC = () => {
  return (
    <MessagePrimitive.Root className="...">
      <div className="...">
        <MessagePrimitive.Parts
          components={{
            Reasoning: Reasoning,
            ReasoningGroup: ReasoningGroup
          }}
        />
      </div>
      <AssistantActionBar />
      <BranchPicker className="..." />
    </MessagePrimitive.Root>
  );
};

How It Works

The component consists of two parts:

  1. Reasoning: Renders individual reasoning message part content (with markdown support)
  2. ReasoningGroup: Wraps consecutive reasoning parts in a collapsible container

Consecutive reasoning parts are automatically grouped together by the ReasoningGroup component.

When using the composable API, Reasoning.Text is a plain container. Add <MarkdownText /> for markdown rendering.

Variants

Use the variant prop on Reasoning.Root to change the visual style:

<Reasoning.Root variant="outline">...</Reasoning.Root>
<Reasoning.Root variant="muted">...</Reasoning.Root>
VariantDescription
defaultNo additional styling
mutedMuted background
outlineRounded border

ReasoningGroup

ReasoningGroup wraps consecutive reasoning parts in a collapsible container. It auto-expands during streaming.

import { ReasoningGroup } from "@/components/assistant-ui/reasoning";

const ReasoningGroupImpl: ReasoningGroupComponent = ({
  children,
  startIndex,
  endIndex,
}) => {
  const isReasoningStreaming = useAuiState((s) => {
    if (s.message.status?.type !== "running") return false;
    const lastIndex = s.message.parts.length - 1;
    if (lastIndex < 0) return false;
    const lastType = s.message.parts[lastIndex]?.type;
    if (lastType !== "reasoning") return false;
    return lastIndex >= startIndex && lastIndex <= endIndex;
  });

  return (
    <ReasoningRoot defaultOpen={isReasoningStreaming}>
      <ReasoningTrigger active={isReasoningStreaming} />
      <ReasoningContent aria-busy={isReasoningStreaming}>
        <ReasoningText>{children}</ReasoningText>
      </ReasoningContent>
    </ReasoningRoot>
  );
};

API Reference

Composable API

All sub-components are exported for custom layouts:

ComponentDescription
Reasoning.RootCollapsible container with scroll lock
Reasoning.TriggerButton with icon, label, and shimmer
Reasoning.ContentAnimated collapsible content wrapper
Reasoning.TextText wrapper with slide/fade animation
Reasoning.FadeGradient fade overlay at bottom
import {
  Reasoning,
  ReasoningRoot,
  ReasoningTrigger,
  ReasoningContent,
  ReasoningText,
  ReasoningFade,
} from "@/components/assistant-ui/reasoning";

// Compound component syntax
<Reasoning.Root variant="muted">
  <Reasoning.Trigger active={isStreaming} />
  <Reasoning.Content>
    <Reasoning.Text>{children}</Reasoning.Text>
  </Reasoning.Content>
</Reasoning.Root>
  • ToolGroup - Similar grouping pattern for tool calls
  • PartGrouping - Experimental API for grouping message parts