Skip to content
Scrim UI

Reasoning Level UI

A control for how hard the model should think — light, balanced or deep, with the tradeoff between speed and depth shown.

reasoningeffortcontrolsettings

Preview

Reasoning effort

Balanced

A 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-level

Follows 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-level

Component 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
reasoning-level.tsx
"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