Reasoning

Collapsible UI for displaying AI reasoning and thinking messages.

Outline (default)
Ghost
Muted

Getting Started

Add reasoning

npx shadcn@latest add @assistant-ui/reasoning

The @assistant-uinamespace resolves the Radix or Base UI flavor from your project's style through the style-aware registry entry in components.json. Without that entry, add by direct URL instead:

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

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

Use in your application

Previously, reasoning parts were rendered via components.Reasoning and grouped via components.ReasoningGroup on MessagePrimitive.Parts. Both are deprecated; MessagePrimitive.GroupedParts is the supported replacement, and the highlighted lines below show the new pieces.

Render reasoning parts through MessagePrimitive.GroupedParts. Group consecutive reasoning parts with "group-reasoning", then compose ReasoningRoot, ReasoningTrigger, ReasoningContent, and ReasoningText around the grouped children.

While reasoning is streaming, part.status.type === "running". Pass that to streaming so the accordion auto-opens during streaming with a bottom-pinned live preview of the newest tokens, auto-collapses when the model moves on, and permanently defers to the first manual toggle. When streaming is provided it supersedes defaultOpen.

/app/components/assistant-ui/thread.tsx
import { MessagePrimitive, groupPartByType } from "@assistant-ui/react";
import { MarkdownText } from "@/components/assistant-ui/markdown-text";
import { ToolFallback } from "@/components/assistant-ui/tool-fallback";
import {
  Reasoning,
  ReasoningContent,
  ReasoningRoot,
  ReasoningText,
  ReasoningTrigger,
} from "@/components/assistant-ui/reasoning";

const AssistantMessage: FC = () => {
  return (
    <MessagePrimitive.Root className="...">
      <div className="...">
        <MessagePrimitive.GroupedParts
          groupBy={groupPartByType({
            reasoning: ["group-reasoning"],
          })}
        >
          {({ part, children }) => {
            switch (part.type) {
              case "group-reasoning": {
                const running = part.status.type === "running";
                return ( 
                  <ReasoningRoot streaming={running}>
                    <ReasoningTrigger active={running} />
                    <ReasoningContent aria-busy={running}>
                      <ReasoningText>{children}</ReasoningText>
                    </ReasoningContent>
                  </ReasoningRoot>
                );
              }
              case "text":
                return <MarkdownText />;
              case "reasoning":
                return <Reasoning {...part} />;
              case "tool-call":
                return part.toolUI ?? <ToolFallback {...part} />;
              default:
                return null;
            }
          }}
        </MessagePrimitive.GroupedParts>
      </div>
      <AssistantActionBar />
      <BranchPicker className="..." />
    </MessagePrimitive.Root>
  );
};

GroupedParts calls your render function for both group nodes and leaf parts. The case "group-reasoning" branch renders the collapsible shell and must render {children}; that is where the individual reasoning parts get placed. The case "reasoning" branch renders each individual reasoning part inside that shell and must not render children. Removing either case breaks rendering.

How It Works

The component consists of two parts:

  1. Reasoning: Renders individual reasoning message part content (with markdown support)
  2. Composable group pieces (ReasoningRoot, ReasoningTrigger, ReasoningContent, ReasoningText): Wrap grouped reasoning children in a collapsible container

Consecutive reasoning parts are grouped by MessagePrimitive.GroupedParts. Use the composable API below to control the grouped layout.

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

Variants

Use the variant prop on ReasoningRoot to change the visual style:

<ReasoningRoot variant="outline">...</ReasoningRoot>
<ReasoningRoot variant="ghost">...</ReasoningRoot>
<ReasoningRoot variant="muted">...</ReasoningRoot>
VariantDescription
outlineRounded border (default)
ghostNo additional styling
mutedMuted background

Legacy ReasoningGroup

ReasoningGroup is kept for existing code that still uses the deprecated components.ReasoningGroup prop on MessagePrimitive.Parts. New code should use MessagePrimitive.GroupedParts and compose the root/trigger/content pieces directly.

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 streaming={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
ReasoningRootCollapsible container with scroll lock
ReasoningTriggerButton with icon, label, and shimmer
ReasoningContentAnimated collapsible content wrapper
ReasoningTextText wrapper with slide/fade animation
ReasoningFadeGradient fade overlay at bottom
import {
  ReasoningRoot,
  ReasoningTrigger,
  ReasoningContent,
  ReasoningText,
  ReasoningFade,
} from "@/components/assistant-ui/reasoning";

<ReasoningRoot variant="muted">
  <ReasoningTrigger active={isStreaming} />
  <ReasoningContent>
    <ReasoningText>{children}</ReasoningText>
  </ReasoningContent>
</ReasoningRoot>
  • ToolGroup - Similar grouping pattern for tool calls
  • PartGrouping - Advanced grouping options for message parts