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
First install and activate one skin. Core deliberately contains no visual token defaults.
This agent installs from the markdown-block registry. Install the bundle with the command above, or inspect the source below.
npx shadcn@latest add https://control-ui.dev/r/markdown-block.jsonUsage
import { MarkdownBlock, MarkdownBlockContent, MarkdownBlockCopy, MarkdownBlockHeader, MarkdownBlockTitle,} from "@/components/control-ui/markdown-block";export function Example({ markdown }: { markdown: string }) { return ( <MarkdownBlock code={markdown}> <MarkdownBlockHeader> <MarkdownBlockTitle /> <MarkdownBlockCopy /> </MarkdownBlockHeader> <MarkdownBlockContent /> </MarkdownBlock> );}Knobs
Typed custom properties the recipe paints with. Set one on the root — style, a utility class, or a skin — and every slot inherits it.
--cui-markdown-block-* · 6 knobsHow the cascade resolves--cui-markdown-block-radius<length-percentage>var(--radius-panel)--cui-markdown-block-background<color>var(--background)--cui-markdown-block-border-color<color>var(--border)--cui-markdown-block-shadow*var(--shadow-sm)--cui-markdown-block-header-border-color<color>var(--border)--cui-markdown-block-icon-background<color>oklch(from var(--foreground) l c h / 0.08)Installed dependencies
Private support files installed with this agent. Public library dependencies stay linked to their own pages.
src/registry/hooks/use-copy-to-clipboard.tsHookLibrary dependencies
Public registry items keep their source on their own documentation page instead of duplicating it here.
Raw code
This agent's owned source and private support files
"use client";import type { ComponentProps, CSSProperties } from "react";import { createContext, useContext } from "react";import type { MarkdownBlockKnobStyle } from "@/components/control-ui/knob-contracts/markdown-block-knobs";import { cn } from "@/components/control-ui/lib/cn";import { CodeCopy, type CodeCopyProps } from "@/components/control-ui/ui/code";import { Markdown } from "@/components/control-ui/ui/markdown";const MarkdownBlockContext = createContext<string | null>(null);function useMarkdownBlockContext() { const code = useContext(MarkdownBlockContext); if (code === null) throw new Error("MarkdownBlock compound components must be rendered inside <MarkdownBlock>."); return code;}export type MarkdownBlockProps = Omit<ComponentProps<"figure">, "style"> & { code: string; style?: CSSProperties & MarkdownBlockKnobStyle;};export function MarkdownBlock({ code, className, children, ...props }: MarkdownBlockProps) { return ( <MarkdownBlockContext.Provider value={code}> <figure data-control-ui="markdown-block" data-control-family="markdown-block" data-slot="root" data-surface="panel" className={cn("my-4 overflow-hidden", className)} {...props} > {children} </figure> </MarkdownBlockContext.Provider> );}export type MarkdownBlockHeaderProps = Omit<ComponentProps<"figcaption">, "style"> & { style?: CSSProperties & MarkdownBlockKnobStyle;};export function MarkdownBlockHeader({ className, ...props }: MarkdownBlockHeaderProps) { return ( <figcaption data-control-ui="markdown-block" data-control-family="markdown-block" data-slot="header" className={cn("sticky top-0 z-10 flex items-center justify-between gap-3 px-4 py-2", className)} {...props} /> );}export type MarkdownBlockTitleProps = Omit<ComponentProps<"div">, "style"> & { style?: CSSProperties & MarkdownBlockKnobStyle;};export function MarkdownBlockTitle({ children = "Markdown", className, ...props }: MarkdownBlockTitleProps) { return ( <div data-control-ui="markdown-block" data-control-family="markdown-block" data-slot="title" className={cn("flex min-w-0 items-center gap-2", className)} {...props} > <span aria-hidden="true" data-control-ui="markdown-block" data-control-family="markdown-block" data-slot="title-icon" className="flex size-5 items-center justify-center" > MD </span> <span className="truncate">{children}</span> </div> );}export type MarkdownBlockCopyProps = Omit<CodeCopyProps, "value">;// IS CodeCopy, so markdown block's copy and a code block's copy can never driftexport function MarkdownBlockCopy({ "aria-label": ariaLabel = "Copy markdown", ...props }: MarkdownBlockCopyProps) { const code = useMarkdownBlockContext(); return <CodeCopy value={code} aria-label={ariaLabel} {...props} />;}export type MarkdownBlockContentProps = ComponentProps<"div"> & { style?: CSSProperties & MarkdownBlockKnobStyle };export function MarkdownBlockContent({ children, className, ...props }: MarkdownBlockContentProps) { const code = useMarkdownBlockContext(); return ( <div data-control-ui="markdown-block" data-control-family="markdown-block" data-slot="content" className={cn("max-h-[420px] overflow-auto mask-y-from-[calc(100%_-_var(--scroll-fade-size))] p-4", className)} {...props} > {children ?? <Markdown content={code} />} </div> );}