Refined UI

An opinionated, customizable superset of shadcn/ui

AgentsPrimitivesSkillsSkins
Integration
Guides
  • Overview
  • Get started
  • Shadcn compatibility
  • Architecture
  • Agent surface
Agents
  • Action Bar
  • Audio Recorder
  • Audio VisualizerBetaBeta — the props contract is close to final, but small breaking changes can still land.
  • Chat Input
  • Chat Input Attachment
  • Chat Message
  • Chat Scene
  • Code Block Editor
  • Dynamic NotificationExpExperimental — the contract and the rendering can change without notice. Own the installed copy before shipping it.
  • Environment Variables
  • Inline Attachment
  • Markdown Block
  • Task List
  • Thread Rail
  • Tool Call
  • User Ask
Blocks
  • Chat
  • Theme toggle
  1. Agents
  2. ThreadRail
Agents

ThreadRail

Conversation minimap for scanning and jumping between chat turns.

Composition

The preferred shape for composing the installed agent from its exported parts.

Parts

Exported compound parts from the installed source.

ThreadRail
├── ThreadRailItem
├── ThreadRailLine
├── ThreadRailPopover
├── ThreadRailTitle
├── ThreadRailSummary
├── ThreadRailFooter
├── ThreadRailFile
├── ThreadRailFileIcon
└── ThreadRailMore

This agent installs from the chat registry. Install the bundle with the command above, or inspect the source below.

Registry command
npx shadcn@latest add http://127.0.0.1:3000/r/refined/chat.json
See registry manifest

Usage

import {
ThreadRail,
ThreadRailFile,
ThreadRailFileIcon,
ThreadRailFooter,
ThreadRailItem,
ThreadRailLine,
ThreadRailMore,
ThreadRailPopover,
ThreadRailSummary,
ThreadRailTitle,
} from "@/components/refined-ui/thread-rail";
​
// Host app maps its conversation into plain ThreadRail props: one tick per user message, popover shows prompt + part of reply.
type UserTurn = {
id: string;
prompt: string;
reply: string;
files: string[];
};
​
export function Example({ turns, inViewId }: { turns: UserTurn[]; inViewId?: string }) {
return (
<ThreadRail>
{turns.map((turn) => {
const visible = turn.files.slice(0, 2);
const overflow = turn.files.length - visible.length;
​
return (
<ThreadRailItem key={turn.id} inView={turn.id === inViewId}>
<ThreadRailLine aria-label={turn.prompt} />
<ThreadRailPopover>
<ThreadRailTitle>{turn.prompt}</ThreadRailTitle>
<ThreadRailSummary>{turn.reply}</ThreadRailSummary>
{turn.files.length > 0 ? (
<ThreadRailFooter>
{visible.map((file) => (
<ThreadRailFile key={file}>
<ThreadRailFileIcon>#</ThreadRailFileIcon>
{file}
</ThreadRailFile>
))}
{overflow > 0 ? <ThreadRailMore>+{overflow}</ThreadRailMore> : null}
</ThreadRailFooter>
) : null}
</ThreadRailPopover>
</ThreadRailItem>
);
})}
</ThreadRail>
);
}
​

Installed dependencies

Installed with this agent because the visible component depends on them; they are support files, not separate product surfaces.

Interaction layersrc/registry/sources/refined/thread-rail.cssSupport
Surface variantssrc/registry/sources/refined/surface-variants.tsSupport

Raw code

Primary installed agent source

Component
src/registry/sources/refined/thread-rail.tsx

On this page

  • Preview
  • Composition
  • Installation
  • Usage
  • Dependencies
  • Source
scaffold the turborepo workspace

Created apps/docs and packages/skills with a shared tsconfig and turbo pipelines.

add a shadcn registry

Added registry/ manifests and a generated public/r mirror so installs use real URLs.

#chat.json
make installs copy source files

Each manifest maps src/registry files to components/refined-ui targets, so the app owns the code.

write a refined skin

Added a compact, rounded, Notion-like skin across every documented component.

keep skins runner-agnostic

Validation now fails if a skin imports @mastra/react or the ai package.

add tool call states

Mapped pending, running, success, and error to status badges in both skins.

#tool-call.tsx
compose the chat block

Composed scene, messages, input, attachments, markdown, and tools into one recipe.

#chat.tsx
read examples from real files

Docs tabs now read the actual source instead of duplicated strings.

show the mastra mapping

Usage files map runner data into Refined UI props without becoming required runtime code.

fix the typecheck

Resolved the ComponentId union and the example map so tsc --noEmit passes.

use Mono Sans font please

Done. I updated the global docs font stack in globals.css to use "Mono Sans" first. Validated with npm run format:check, npm run lint, and the typecheck.

#globals.css
ship it

Opened a draft PR with the refined skin and the mastra usage mapping.