Reasoning
Overview
The Reasoning component displays AI reasoning or thinking messages in a collapsible UI. Consecutive reasoning message parts are automatically grouped together with smooth animations and a shimmer effect while streaming.
Getting Started
Add reasoning
npx assistant-ui@latest add reasoningnpx shadcn@latest add @assistant-ui/reasoningnpx shadcn@latest add "https://r.assistant-ui.com/reasoning"This adds a /components/assistant-ui/reasoning.tsx file to your project, which you can adjust as needed.
Use in your application
Pass the Reasoning and ReasoningGroup components to the MessagePrimitive.Parts component:
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:
- Reasoning: Renders individual reasoning message part content
- ReasoningGroup: Wraps consecutive reasoning parts in a collapsible container
Consecutive reasoning parts are automatically grouped together by the ReasoningGroup component, similar to how ToolGroup handles tool calls.
Reasoning
The Reasoning component doesn't accept additional props—it renders the reasoning text content with markdown support.
Examples
Basic Usage
<MessagePrimitive.Parts
components={{
Reasoning,
ReasoningGroup
}}
/>Custom Styling
Since the component is copied to your project, you can customize it directly by modifying the reasoning.tsx file. The internal components (ReasoningRoot, ReasoningTrigger, ReasoningContent, ReasoningText) accept className props for styling:
const ReasoningGroupImpl: ReasoningGroupComponent = ({
// ... existing code ...
return (
<ReasoningRoot className="rounded-lg border bg-muted/50 p-4">
<ReasoningTrigger
active={isReasoningStreaming}
className="font-semibold text-foreground"
/>
<ReasoningContent
aria-busy={isReasoningStreaming}
className="mt-2"
>
<ReasoningText className="text-base">{children}</ReasoningText>
</ReasoningContent>
</ReasoningRoot>
);
};You can also customize the individual internal components:
const ReasoningRoot: FC<PropsWithChildren<{ className?: string }>> = ({
// ... existing code ...
return (
<Collapsible
// ...
className={cn("aui-reasoning-root mb-4 w-full rounded-lg border bg-muted/50 p-4", className)}
// ...
>
{children}
</Collapsible>
);
};
const ReasoningTrigger: FC<{ active: boolean; className?: string }> = ({
// ... existing code ...
<CollapsibleTrigger
className={cn(
"aui-reasoning-trigger group/trigger -mb-2 flex max-w-[75%] items-center gap-2 py-2 text-sm font-semibold text-foreground transition-colors hover:text-foreground",
className,
)}
>
{/* ... existing content ... */}
</CollapsibleTrigger>
);Technical Details
Scroll Lock
The component uses the useScrollLock hook (exported from @assistant-ui/react) to prevent page jumps when collapsing the reasoning section. This maintains the scroll position during the collapse animation.
Animation Timing
The component uses CSS custom properties for animation timing:
--animation-duration: Controls expand/collapse animation (default: 200ms)--shimmer-duration: Controls the shimmer effect speed (default: 1000ms)
These can be customized by modifying the CSS variables in your component.
Related Components
- ToolGroup - Similar grouping pattern for tool calls
- PartGrouping - Experimental API for grouping message parts