Browse all components
Reasoning Level UI
A control for how hard the model should think — light, balanced or deep, with the tradeoff between speed and depth shown.
Preview
Reasoning effort
BalancedA good default for most tasks
Presets
Props
Also takes onChange.
Agent promptClaude Code · Cursor · any agent
Add the Reasoning Level UI component from the Scrim UI registry to this project and use it in the configuration described below.
Reasoning Level UI — A control for how hard the model should think — light, balanced or deep, with the tradeoff between speed and depth shown.
## 1. Install
```bash
npx shadcn@latest add @scrimui/reasoning-level
```
This writes a single file to `components/ui/reasoning-level.tsx`. It is plain React + Tailwind with no runtime dependencies — no Radix, no CVA, nothing to add to package.json. If this project does not use the shadcn CLI, copy the source from https://scrimui.dev/components/reasoning-level to the same path by hand; nothing in the file depends on shadcn.
## 2. Use it
```tsx
import { ReasoningLevel } from "@/components/ui/reasoning-level";
<ReasoningLevel
value="balanced"
onChange={() => {}}
/>
```
## 3. The configuration that matters
This is the component's "Balanced" state — A segmented control with a live caption explaining the current choice.
Every prop is at its default value. Keep the call site minimal — do not write out default values.
## 4. Wire the handlers
`onChange` is a stub in the snippet above (`() => {}`). Connect it to this project's own state and data layer instead of shipping the empty function.
Reference: https://scrimui.dev/components/reasoning-levelFollows the props below — change a control and the prompt changes with it, so an agent reproduces that configuration instead of the defaults.
Install
npx shadcn@latest add @scrimui/reasoning-levelComponent source
React + Tailwind component using shadcn/ui (button). The install command adds these dependencies automatically.
When copying source manually, install the required primitives first:
npx shadcn@latest add button"use client";
import { Button } from "@/components/ui/button";
import * as React from "react";
/* ------------------------------------------------------------------ */
/* Types */
/* ------------------------------------------------------------------ */
export type ReasoningLevel = "light" | "balanced" | "deep";
export type ReasoningLevelProps = {
value?: ReasoningLevel;
onChange?: (level: ReasoningLevel) => void;
compact?: boolean;
className?: string;
};
const LEVELS: { id: ReasoningLevel; label: string; hint: string }[] = [
{ id: "light", label: "Light", hint: "Fast answers for simple questions" },
{ id: "balanced", label: "Balanced", hint: "A good default for most tasks" },
{ id: "deep", label: "Deep", hint: "Thinks longer for hard problems" },
];
/* ------------------------------------------------------------------ */
/* ReasoningLevel */
/* ------------------------------------------------------------------ */
export function ReasoningLevel({
value = "balanced",
onChange,
compact = false,
className = "",
}: ReasoningLevelProps) {
const current = LEVELS.find((l) => l.id === value) ?? LEVELS[1];
return (
<div className={className}>
<div className="flex items-center justify-between">
<p className="text-sm font-medium text-foreground">Reasoning effort</p>
<span className="text-xs font-medium text-muted-foreground">
{current.label}
</span>
</div>
<div
role="radiogroup"
aria-label="Reasoning effort"
className="mt-2 grid grid-cols-3 gap-1 rounded-lg bg-muted p-1"
>
{LEVELS.map((level) => {
const active = level.id === current.id;
return (
<Button variant="ghost" size="sm"
key={level.id}
type="button"
role="radio"
aria-checked={active}
onClick={() => onChange?.(level.id)}
className={`rounded-md px-2 py-1.5 text-xs font-medium transition-colors ${
active
? "bg-card text-foreground shadow-sm"
:
"text-muted-foreground hover:text-foreground"
}`}
>
{level.label}
</Button>
);
})}
</div>
{!compact && (
<p className="mt-2 text-xs text-muted-foreground">{current.hint}</p>
)}
</div>
);
}
When to use it
- Name levels by outcome (Light / Balanced / Deep), not internal parameter names.
- Explain the current level in plain words — what will the model do differently?
- Default to the middle option; deep reasoning costs time and money.
- Make the control keyboard accessible with arrow-key movement.
What breaks in production
- Exposing raw numbers or internal API terms the user has to decode.
- No feedback on what changed — switching to Deep and seeing no effect feels broken.
- Letting deep reasoning run silently on every message, burning latency and credits.
Related Components
A standalone model picker — compare models in a dropdown with badges for speed, context length and what each supports.
Switches for the tools a model may use — web search, code execution, file access — with unmistakable on and off states.
Live spend per message and per conversation — cached input priced apart from fresh, reasoning tokens shown without double-counting, and a visible ~ when a provider did not report enough to be sure.
The message input at the heart of an AI chat app — file attachments, model picker, tool toggles, voice, and a send button that turns into stop.