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. MarkdownBlock
Agents

MarkdownBlock

Assistant markdown output rendered to prose, with a header and copy-source action.

Composition

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

Parts

Exported compound parts from the installed source.

MarkdownBlock
├── MarkdownBlockHeader
├── MarkdownBlockTitle
├── MarkdownBlockCopy
└── MarkdownBlockContent

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 {
MarkdownBlock,
MarkdownBlockContent,
MarkdownBlockCopy,
MarkdownBlockHeader,
MarkdownBlockTitle,
} from "@/components/refined-ui/markdown-block";
​
export function Example({ markdown }: { markdown: string }) {
return (
<MarkdownBlock code={markdown}>
<MarkdownBlockHeader>
<MarkdownBlockTitle />
<MarkdownBlockCopy />
</MarkdownBlockHeader>
<MarkdownBlockContent />
</MarkdownBlock>
);
}
​

Installed dependencies

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

Copy hooksrc/registry/hooks/use-copy-to-clipboard.tsHook

Raw code

Primary installed agent source

Component
src/registry/sources/refined/markdown-block.tsx
"use client";
​
import type { ComponentProps, MouseEvent } from "react";
import { createContext, useContext } from "react";
import { useCopyToClipboard } from "@/components/refined-ui/hooks/use-copy-to-clipboard";
import { cn } from "@/components/refined-ui/lib/cn";
import { skinSlot } from "@/components/refined-ui/skin";
import { Button } from "@/components/refined-ui/ui/button";
import { Markdown } from "@/components/refined-ui/ui/markdown";
​
type MarkdownBlockContextValue = {
code: string;
};
​
const MarkdownBlockContext = createContext<MarkdownBlockContextValue | null>(null);
​
function useMarkdownBlockContext() {
const context = useContext(MarkdownBlockContext);
if (!context) throw new Error("MarkdownBlock compound components must be rendered inside <MarkdownBlock>.");
return context;
}
​
export type MarkdownBlockProps = ComponentProps<"figure"> & {
code: string;
};
​
export function MarkdownBlock({ code, className, children, ...props }: MarkdownBlockProps) {
return (
<MarkdownBlockContext.Provider value={{ code }}>
<figure
data-ui="agent"
data-component="markdown-block"
className={cn(
"my-4 overflow-hidden rounded-panel border bg-muted shadow-sm ring-1 ring-foreground/4",
skinSlot("markdown-block", {}),
className,
)}
{...props}
>
{children}
</figure>
</MarkdownBlockContext.Provider>
);
}
​
export type MarkdownBlockHeaderProps = ComponentProps<"figcaption">;
​
export function MarkdownBlockHeader({ className, ...props }: MarkdownBlockHeaderProps) {
return (
<figcaption
className={cn(
"sticky top-0 z-10 flex items-center justify-between gap-3 border-b px-4 py-2",
skinSlot("markdown-block-header", {}),
className,
)}
{...props}
/>
);
}
​
export type MarkdownBlockTitleProps = ComponentProps<"div">;
​
export function MarkdownBlockTitle({ children = "Markdown", className, ...props }: MarkdownBlockTitleProps) {
return (
<div className={cn("flex min-w-0 items-center gap-2 text-sm font-medium", skinSlot("markdown-block-title", {}), className)} {...props}>
<span aria-hidden="true" className="flex size-5 items-center justify-center rounded-md bg-foreground/8 text-micro">
MD
</span>
<span className="truncate">{children}</span>
</div>
);
}
​
export type MarkdownBlockCopyProps = ComponentProps<typeof Button>;
​
export function MarkdownBlockCopy({ children = "Copy", onClick, ...props }: MarkdownBlockCopyProps) {
const { code } = useMarkdownBlockContext();
const { copyToClipboard } = useCopyToClipboard();
​
function copyCode(event: MouseEvent<HTMLButtonElement>) {
onClick?.(event);
if (!event.defaultPrevented) void copyToClipboard(code);
}
​
return (
<Button variant="quiet" size="xs" onClick={copyCode} {...props}>
{children}
</Button>
);
}
​
export type MarkdownBlockContentProps = ComponentProps<"div">;
​
export function MarkdownBlockContent({ children, className, ...props }: MarkdownBlockContentProps) {
const { code } = useMarkdownBlockContext();
​
return (
<div className={cn("scroll-fade max-h-[420px] overflow-auto p-4", skinSlot("markdown-block-content", {}), className)} {...props}>
{children ?? <Markdown content={code} />}
</div>
);
}
​

Primitives

This agent composes these library primitives, installed under components/refined-ui/ui/*.

Buttoncomponents/refined-ui/ui/button.tsxLibrary slotMarkdowncomponents/refined-ui/ui/markdown.tsxLibrary slot

On this page

  • Preview
  • Composition
  • Installation
  • Usage
  • Dependencies
  • Source
  • Primitives
MDMarkdown

Notes

Memory / Studio / Platform / Gallery

  • Design mode in foreground UI
    • Import in website / other
  • Text editor with [?] modes

Core ideas

  • Safe area for text edit
  • Resize -> mobile

Possible components / tools

  • Motion / video
  • Full-screen
  • Mini-browser
  • Animation
  • Agent slot
  • Extension
  • Demo / memory stream
  • Game slot
  • Workflow grid panel / scene / mini
  • Predefined memory for vibe

UX / Website Builder

  • You always need to branch
    • Less is more
  • Hierarchy is the key
    • Think about advanced users
    • Estimate how complex the feature is
    • Check if the user can understand it

Open Question

Should we have rules about what is beautiful design?