Reasoning
nexus-ui/reasoningFreeComponent
Collapsible model reasoning trace with streaming-aware labels and markdown body
Live preview
live · rendered by the registry
Rendered by nexus-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://nexus-ui.dev/r/reasoning.jsonSource
1"use client";23import * as React from "react";4import { AiBrain01Icon, ArrowDown01Icon } from "@hugeicons/core-free-icons";5import { HugeiconsIcon } from "@hugeicons/react";6import { Streamdown } from "streamdown";78import {9 Collapsible,10 CollapsibleContent,11 CollapsibleTrigger,12} from "@/components/ui/collapsible";13import { TextShimmer } from "@/components/nexus-ui/text-shimmer";14import { useOnChange } from "@/lib/use-on-change";15import { cn } from "@/lib/utils";1617type ReasoningContextValue = {18 isStreaming: boolean;19 label: string;20};2122const ReasoningContext = React.createContext<ReasoningContextValue | null>(23 null,24);2526function useReasoningContext(component: string): ReasoningContextValue {27 const ctx = React.useContext(ReasoningContext);28 if (!ctx) {29 throw new Error(`${component} must be used within <Reasoning>`);30 }31 return ctx;32}3334type ReasoningProps = Omit<35 React.ComponentProps<typeof Collapsible>,36 "open" | "defaultOpen" | "onOpenChange"37> & {38 isStreaming?: boolean;39 open?: boolean;40 defaultOpen?: boolean;41 onOpenChange?: (open: boolean) => void;42};4344function Reasoning({45 className,46 isStreaming = false,47 open: openProp,48 defaultOpen = false,49 onOpenChange,50 children,51 ...props52}: ReasoningProps) {53 const isControlled = openProp !== undefined;54 const [internalOpen, setInternalOpen] = React.useState(55 defaultOpen || isStreaming,56 );57 const open = isControlled ? openProp : internalOpen;58 const [durationLabel, setDurationLabel] = React.useState<string | null>(null);59 const [hasStreamed, setHasStreamed] = React.useState(isStreaming);60 const startedAtRef = React.useRef<number | null>(null);6162 React.useEffect(() => {63 if (isStreaming) {64 startedAtRef.current = Date.now();65 onOpenChange?.(true);66 }67 }, [isStreaming, onOpenChange]);6869 useOnChange(isStreaming, (current, previous) => {70 if (!previous && current) {71 setHasStreamed(true);72 startedAtRef.current = Date.now();73 setDurationLabel(null);74 if (!isControlled) {75 setInternalOpen(true);76 }77 onOpenChange?.(true);78 }7980 if (previous && !current) {81 const startedAt = startedAtRef.current;82 const elapsedSeconds =83 startedAt != null84 ? Math.max(1, Math.round((Date.now() - startedAt) / 1000))85 : null;86 setDurationLabel(87 elapsedSeconds != null ? String(elapsedSeconds) : "a few",88 );89 startedAtRef.current = null;90 if (!isControlled) {91// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from nexus-ui
All 15 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Attachmentsattachments | nexus-ui | Components | Free | 4 deps · 2 files | |
| Chain of Thoughtchain-of-thought | nexus-ui | Components | Free | 2 deps · 2 files | |
| Citationcitation | nexus-ui | Components | Free | 4 deps | |
| Feedback Barfeedback-bar | nexus-ui | Components | Free | 1 dep | |
| Imageimage | nexus-ui | Components | Free | 2 deps | |
| Messagemessage | nexus-ui | Components | Free | 9 deps · 2 files | |
| Model Selectormodel-selector | nexus-ui | Components | Free | 3 deps | |
| Prompt Inputprompt-input | nexus-ui | Components | Free | 1 dep |
