Primitives
Markdown
Rendered agent markdown (GFM) whose code fences compose Code, and diff fences compose CodeDiff.
Composition
Rendered markdown
Pass the source in content. MarkdownRoot supplies tokens; MarkdownFlow owns block spacing.
- <Markdown>
- <MarkdownRoot>
- <MarkdownFlow>
- rendered prose and code fences
- <MarkdownFlow>
- <MarkdownRoot>
Custom prose
Compose MDX or Markdown parts inside MarkdownFlow. Re-value --cui-markdown-flow-gap and --cui-markdown-heading-gap on MarkdownRoot.
- <MarkdownRoot>
- <MarkdownFlow>
- consumer-rendered prose
- <MarkdownFlow>
Installation
First install and activate one skin. Core deliberately contains no visual token defaults.
The Control UI source installs this primitive from src/registry/sources/control-ui/ui/markdown.tsx.
npx shadcn@latest add https://control-ui.dev/r/markdown.jsonDependencies
Markdown elements
src/registry/sources/control-ui/ui/markdown-elements.tsxSupportDiff engine
src/registry/lib/diff.tsSupportShiki tokenizer
src/registry/lib/code-tokens.tsSupportCode + diff tokens
Checkboxsrc/registry/sources/control-ui/code.cssSupportcheckboxPrimitiveCodecodePrimitiveCode Diffcode-diffPrimitiveScroll areascroll-areaPrimitiveTypographytypographyPrimitiveRaw code
Primary installed source
"use client";import type { ComponentProps, CSSProperties } from "react";import { Streamdown } from "streamdown";import type { MarkdownKnobStyle } from "@/components/control-ui/knob-contracts/markdown-knobs";import { cn } from "@/components/control-ui/lib/cn";import { markdownComponents } from "@/components/control-ui/ui/markdown-elements";export type MarkdownRootProps = Omit<ComponentProps<"div">, "style"> & { style?: CSSProperties & MarkdownKnobStyle;};export type MarkdownProps = Omit<MarkdownRootProps, "children"> & { content: string; mode?: "streaming" | "static" };export function MarkdownRoot({ className, ...props }: MarkdownRootProps) { return ( <div data-control-ui="markdown" data-control-family="markdown" data-slot="root" className={cn("[&>*:first-child]:mt-0 [&>*:last-child]:mb-0", className)} {...props} /> );}export function MarkdownFlow(props: MarkdownRootProps) { return <div data-control-ui="markdown" data-control-family="markdown" data-slot="flow" {...props} />;}export function Markdown({ content, mode = "streaming", className, ...props }: MarkdownProps) { return ( <MarkdownRoot className={className} {...props}> <MarkdownFlow> {/* Streamdown's wrapper drops DOM props and adds utility margins. */} <Streamdown mode={mode} parseIncompleteMarkdown={mode === "streaming"} controls={false} components={markdownComponents} className="cui-markdown-streamdown [&>[data-control-family]]:[margin-block:revert-layer]" > {content} </Streamdown> </MarkdownFlow> </MarkdownRoot> );}export type MarkdownComponentProps = ComponentProps<typeof Markdown>;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-* · 14 knobsHow the cascade resolves--cui-markdown-foreground<color>oklch(from var(--foreground) l c h / 0.9)--cui-markdown-blockquote-border-color<color>var(--border)--cui-markdown-blockquote-foreground<color>var(--muted-foreground)--cui-markdown-inline-code-background<color>color-mix(in oklab, var(--foreground) 8%, transparent)--cui-markdown-inline-code-foreground<color>var(--foreground)--cui-markdown-inline-code-radius<length-percentage>+0.25rem--cui-markdown-link-foreground<color>var(--primary-text)--cui-markdown-image-outline-color<color>var(--image-outline)--cui-markdown-table-cell-border-color<color>var(--border)--cui-markdown-table-header-background<color>var(--muted)--cui-markdown-font-size<length-percentage>var(--text-body)--cui-markdown-line-height<number>var(--leading-relaxed)--cui-markdown-flow-gap<length-percentage>calc(var(--spacing) * 4)--cui-markdown-heading-gap<length-percentage>calc(var(--spacing) * 6)