Thinking Block
Collapsible block showing AI thinking/reasoning with streaming support. Install Thinking Block from the VLLNT UI registry with the shadcn CLI.
When to use this in an AI app
Use Thinking Block to reveal an agent's reasoning or scratchpad separately from its final answer. Collapsible plus streaming support keeps the transcript clean while staying transparent.
Browse all AI agent componentsCollapsible block showing AI thinking/reasoning with streaming support. Part of the ai family in VLLNT UI, it ships as a machine-readable registry entry — copy the source directly into your app with the shadcn CLI and own it, no runtime dependency on a component library.
Preview
Switch between light and dark to inspect the embedded Storybook preview.
Installation
Add Thinking Block to your project with the shadcn CLI. The source lands in your codebase, ready to adapt:
pnpm dlx shadcn@latest add https://ui.vllnt.ai/r/thinking-block.jsonSource
"use client";
import { useCallback, useEffect, useId, useState } from "react";
import { ChevronDown, ChevronRight } from "lucide-react";
import { cn } from "../../lib/utils";
export type ThinkingBlockProps = {
className?: string;
/** Whether the content is still streaming. */
isStreaming?: boolean;
/** The thinking text content to display. */
thinking: string;
};
/** Collapsible thinking block with streaming support. */
export function ThinkingBlock({
className,
isStreaming = false,
thinking,
}: ThinkingBlockProps) {
const [isExpanded, setIsExpanded] = useState(() => isStreaming);
const contentId = useId();
// Auto-open when streaming starts
useEffect(() => {
if (isStreaming) {
requestAnimationFrame(() => {
setIsExpanded(true);
});
}
}, [isStreaming]);
const toggleExpanded = useCallback(() => {
setIsExpanded((previous) => !previous);
}, []);
return (
<div className={cn("mb-2", className)}>
<button
aria-controls={contentId}
aria-expanded={isExpanded}
className="flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground transition-colors"
onClick={toggleExpanded}
type="button"
>
{isExpanded ? (
<ChevronDown className="size-3" />
) : (
<ChevronRight className="size-3" />
)}
<span>
Thinking
{isStreaming ? (
<span className="ml-1 animate-pulse">…</span>
) : null}
</span>
</button>
{isExpanded ? (
<div
className="mt-2 p-3 bg-muted/50 rounded text-xs text-muted-foreground whitespace-pre-wrap border-l border-muted-foreground/30 max-h-48 overflow-y-auto"
id={contentId}
>
{thinking}
{isStreaming ? <span className="animate-pulse">|</span> : null}
</div>
) : null}
</div>
);
}
Stories
Explore every variant and state in the interactive Storybook:
Preview
Switch between light and dark to inspect the embedded Storybook preview.