Reasoning Trace
spectrumui/reasoning-traceFreeBlock
An expandable chain-of-thought trace with a live thinking timer.
Install it
npx shadcn@latest add https://ui.spectrumhq.in/r/reasoning-trace.jsonSource
1"use client";23import { useEffect, useRef, useState } from "react";4import { ChevronDown, Sparkles } from "lucide-react";5import { cn } from "@/lib/utils";6import type { ReasoningStep } from "./types";78const KEYFRAMES = `9@keyframes su-shimmer-text { 0% { background-position: 200% 0 } 100% { background-position: -200% 0 } }10@keyframes su-step-in { from { opacity: 0; transform: translateY(4px) } to { opacity: 1; transform: none } }11`;1213export type ReasoningTraceVariant = "Steps" | "Reasoning";1415export interface ReasoningTraceProps {16 steps: ReasoningStep[];17 status: "thinking" | "complete";18 durationMs?: number;19 variant?: ReasoningTraceVariant;20 defaultOpen?: boolean;21 className?: string;22}2324function useThinkingClock(active: boolean) {25 const [ds, setDs] = useState(0);26 const wasActive = useRef(active);27 useEffect(() => {28 if (active && !wasActive.current) setDs(0);29 wasActive.current = active;30 if (!active) return;31 const t = setInterval(() => setDs((d) => d + 1), 100);32 return () => clearInterval(t);33 }, [active]);34 return ds / 10;35}3637export function ReasoningTrace({38 steps,39 status,40 durationMs,41 variant = "Steps",42 defaultOpen = false,43 className,44}: ReasoningTraceProps) {45 const [open, setOpen] = useState(defaultOpen);46 const thinking = status === "thinking";47 const elapsed = useThinkingClock(thinking);4849 const seconds = thinking50 ? elapsed.toFixed(1)51 : ((durationMs ?? elapsed * 1000) / 1000).toFixed(1);5253 return (54 <div className={cn("w-full max-w-[440px] text-[13px]", className)}>55 <style dangerouslySetInnerHTML={{ __html: KEYFRAMES }} />5657 <button58 type="button"59 onClick={() => setOpen((o) => !o)}60 aria-expanded={open}61 className="group flex items-center gap-2 rounded-lg py-1 text-neutral-600 transition-[color,transform] duration-150 hover:text-neutral-900 active:scale-[0.98] focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-neutral-400 dark:text-neutral-400 dark:hover:text-neutral-100"62 >63 <Sparkles64 aria-hidden65 className={cn("size-3.5", thinking && "motion-safe:animate-pulse")}66 />67 {thinking ? (68 <span69 className="bg-clip-text font-medium text-transparent motion-reduce:!animate-none motion-reduce:!text-current"70 style={{71 backgroundImage:72 "linear-gradient(90deg, #a3a3a3 35%, currentColor 50%, #a3a3a3 65%)",73// … truncated
What it pulls in
npm packages
Files it writes
More from spectrumui
All 182 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Agent Planagent-plan | spectrumui | Blocks | Free | 1 dep | |
| Agent Stepsagent-steps | spectrumui | Blocks | Free | 1 dep · 2 files | |
| Approval Cardapproval-card | spectrumui | Blocks | Free | 1 dep | |
| Chat Empty Statechat-empty-state | spectrumui | Blocks | Free | 1 dep · 2 files | |
| Citation Sourcescitation-sources | spectrumui | Blocks | Free | no deps · 2 files | |
| Code Blockcode-block | spectrumui | Blocks | Free | 1 dep | |
| Conversation Listconversation-list | spectrumui | Blocks | Free | 1 dep | |
| Diff Viewdiff-view | spectrumui | Blocks | Free | 1 dep |
