Thinking indicator
Thinking indicator with a pixel wave and a rolling seconds counter; when finished it reads "Thought for Ns" and expands to show the reasoning.
Playground
Change a prop and the component re-renders. Props marked remounts set an initial value, so the component starts over.
<UiThinking>Effort levels change how long the model reasons. Ultracode also lets the model plan multi-agent workflows on its own.</UiThinking>
Installation
pnpm dlx shadcn@latest add @lumesec/ui-thinkingFirst timeRegister the @lumesec registry once, or install by URL+
Adds @lumesec to your components.json:
pnpm dlx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.jsonOr skip the setup and install by URL:
npx shadcn@latest add https://elements.lumesec.ai/r/ui-thinking.jsonUsage
"use client";
import * as React from "react";
import { UiThinking } from "@/components/lumesec/ui-thinking";
export function Example() {
const [done, setDone] = React.useState(false);
React.useEffect(() => {
const timer = window.setTimeout(() => setDone(true), 4000);
return () => window.clearTimeout(timer);
}, []);
return (
<UiThinking done={done} onDone={(seconds) => console.log(`thought for ${seconds}s`)}>
The reasoning, shown once thinking is done.
</UiThinking>
);
}Behaviour
A pixel wave and a shimmering label while the model works, with a seconds counter that rolls on every tick. When it finishes, the glyph draws a check and the label rolls to “Thought for 6s”, which opens the reasoning.
API reference
Props
Also accepts every prop of <div> (React.ComponentProps<"div">), spread onto the root element.
doneTypebooleanWhether thinking has finished (controlled). Use with onDoneChange. When it turns true, the glyph draws a check, the label rolls to "Thought for Ns" and the reasoning becomes expandable. Turning it false returns to thinking; the counter keeps running from the last start.
defaultDoneTypebooleanDefaultfalseWhether it starts finished, when uncontrolled. A component that starts done reads "Thought for 1s".
onDoneChangeType(done: boolean) => voidCalled when finish() or restart() changes the state.
onDoneType(seconds: number) => voidCalled when the state changes to done, with the whole seconds elapsed (at least 1). Not called when the component mounts already done.
childrenTypeReact.ReactNodeThe reasoning, shown in a collapsible panel once done.
Ref
ref receives a UiThinkingHandle handle with these methods.
finish(): voidFinishes thinking. Same as setting done.
restart(): voidResets the counter to 0 and returns to the thinking state, collapsing the reasoning.
Keyboard
| Keys | Action |
|---|---|
| Enter / Space | On the label, once done: show or hide the reasoning. |
Accessibility
- The label is a native
<button>witharia-expanded. It is disabled while thinking and enabled once done; activating it shows or hides the reasoning. - The collapsed reasoning is
inert, so it is neither read nor reachable with Tab until it opens. - The check icon and the pixel-wave canvas are
aria-hidden. - There is no live region, so the counter and the finished label are not announced.
- Reduced motion: the pixel wave holds at a fixed brightness, the label shimmer stops, and the label and counter swap text without rolling.
Theming
Styled with Tailwind classes on your shadcn theme tokens, so light and dark follow your theme. The accent comes from --lumesec. See Theming.
This component reads --lumesec, --lumesec-glint, --foreground, --muted and --muted-foreground.
Notes
- Seconds count from mount, or from
restart(). The counter runs on a timer, so it stays correct while the component is off screen; the wave pauses there. - The labels "Thinking" and "Thought for Ns" are built in English.
Related
Was this page helpful?