neeter

Built-in Widgets

The 11 SDK tool widgets that ship with @neeter/react and how to override them

neeter ships widgets for 11 Claude Agent SDK tools. They auto-register when you import from @neeter/react — just add tools to your SessionManager and the UI handles the rest.

WebSearch widget with favicon source pills

What you get

Every built-in tool renders with three layers:

  1. Approval preview — when permissionMode requires approval, the card shows what the tool is about to do (the file being edited, the command to run, the content being written) so the user can make an informed decision
  2. Loading state — animated indicator while the tool executes
  3. Completed result — formatted output (diff views, code blocks, link pills, checklists)

The collapsed card header shows a rich label — the filename for file tools, the command for Bash, the search query for web tools — instead of the raw tool name.

Covered tools

File operations

ToolApproval previewCompleted resultCollapsed label
ReadFile pathFile content in monospace blockShortened path
WriteFile path + content previewContent that was writtenBasename
EditFile path + red/green diff of old → newConfirmation messageBasename
GlobPattern + search pathMatch count + file listPattern
Grep/{pattern}/ + path, glob, modeSearch results in monospace blockPattern + scope
NotebookEditOperation label, cell ref, code previewOperation result + source block[mode] filename

The Edit widget is the most visually distinct — it shows a line-by-line diff with red/green highlighting so you can see exactly what's changing before approving.

Edit widget: line-by-line diff with approval controls

NotebookEdit uses insert-aware cell labels: for insert operations, the cell reference shows "after cell-2" rather than just "cell-2" since the cell ID is the anchor point.

Command execution

ToolApproval previewCompleted resultCollapsed label
BashDescription + command block$ command + outputDescription or truncated command
Bash widget: command + output with green status dot

Web

ToolApproval previewCompleted resultCollapsed label
WebFetchFavicon pill + domain, promptPill + markdown-rendered contentDomain name
WebSearchSearch queryExpandable grid of favicon + domain pills"query" · N sources
WebFetch widget: favicon pill with markdown-rendered page content

Agent interaction

ToolCompleted resultCollapsed label
AskUserQuestionQuestion/answer pairsHeader: Answer
TodoWriteChecklist with status iconsX/Y done

These two don't show approval previews since they don't go through the canUseTool flow.

TodoWrite checklist with status icons and progress tracking

Tools without widgets

Seven SDK tools intentionally use the default fallback — they produce plain text or are too niche.

ToolReason
TaskSubagent results are plain text
SkillSame as Task
ExitPlanModeSimple confirmation
KillBashSimple confirmation
BashOutputIncremental output, pairs with Bash
ListMcpResourcesNiche, low frequency
ReadMcpResourceNiche, low frequency

Overriding a built-in widget

Call registerWidget with the same toolName to replace any built-in. Your registration wins since side-effect imports run first, and later registrations overwrite earlier ones:

import { registerWidget } from "@neeter/react";

registerWidget({
  toolName: "Bash",
  label: "Terminal",
  component: MyCustomBashWidget,
});

Widget anatomy

Each widget registration can include:

FieldTypePurpose
toolNamestringMatches the SDK tool name (MCP prefixes stripped automatically)
labelstringFallback display name
richLabel(result, input) => string | nullDynamic label for the collapsed card header
inputRendererComponentType<{ input }>Approval preview and queued tool call display
componentComponentType<WidgetProps<T>>Phase-aware result rendering

The inputRenderer serves double duty — it renders in both the approval card (with Allow/Deny buttons) and in queued tool calls waiting for earlier approvals to resolve.

Source files: packages/react/src/widgets/*Widget.tsx | Registry: packages/core/src/registry.ts

Next steps

To register widgets for your own MCP tools or app-specific rendering, see Custom Widgets.

On this page