Code

Markdown

Markdown that can stream: unfinished syntax is repaired as it arrives, only the last block re-renders, and code fences render through Shiki without layout jumps. RemoteImageGate holds an image from another site until it is asked for.

Live example

Import

Each family is its own entry point, so a page loads only what it uses.

tsx
import { Button } from "@nibapp/ui/components/button";import { Markdown } from "@nibapp/ui/components/markdown";import { RemoteImageGate } from "@nibapp/ui/components/remote-image-gate";

Props

Each component's own props and variants, read from its source. What it also takes from an element or a Base UI part is named below its table.

Button

PropTypeDefaultDescription
variant"primary" | "secondary" | "ghost" | "quiet" | "danger" | "danger-ghost" | "link""secondary"
primary
Neutral ink: the main call to action. Actions are ink, never the accent.
secondary
Quiet surface with a hairline — the default for most actions.
ghost
No chrome until hovered — toolbars, inline actions.
quiet
Words that are also an action, in the text's own weight and laid out from the start, so they line up with the text around them: `xs` in a line (a header's crumbs, a title that renames), `sm` a toolbar's picker, `md` a row in a list or a popover ("Open settings", a sidebar's link).
danger
Destructive confirmation.
danger-ghost
Destructive but low emphasis.
link
Inline text action.
size"xs" | "sm" | "md" | "lg""md"
blockboolean—
truncateboolean—

The button may shrink below its label's width; the label then truncates with an ellipsis.

wrapboolean—

The label wraps onto more lines and the button grows, its `leading` icon on the first line: for words that are an action and may run long in another language (a tip). One line keeps the size.

loadingbooleanfalse

Shows a spinner, keeps the button's width, and blocks interaction.

leadingReactNode—

Icon rendered before the label.

trailingReactNode—

Icon or hint (e.g. <Kbd>) rendered after the label.

disabledReasonstring | undefined—

Disables the button and says why: the reason is its tooltip and its accessible description, and the button stays focusable (`aria-disabled`) so a keyboard reaches it.

Also takes .

Markdown

Assistant-message renderer: GFM, Shiki code blocks, calm prose rhythm, streaming-safe.

PropTypeDefaultDescription
children (required)string—

Markdown source.

streamingbooleanfalse

The text is still arriving: repairs unfinished syntax and only re-renders the last block.

measurebooleanfalse

Constrain line length to a comfortable ~72ch measure.

allowImageHostsreadonly string[] | undefined—

Remote image hosts trusted to load on render (e.g. the host's own CDN). Other http(s) images show a "Load image" placeholder until the reader asks; data:, blob: and same-origin always load.

codeActionsCodeBlockActions | undefined—

Extra controls for each finished code block (none by default).

Also takes the props of a <div> element, except children.

RemoteImageGate

A remote image waits for the reader: untrusted content (generated or pasted markdown, a url-kind image part) must not fetch — and leak — the moment it renders, on any surface, CSP or not. Same-origin, relative, data: and blob: images render at once; a cross-origin http(s) one shows what it is and where from, and "Load image" fetches it on purpose.

PropTypeDefaultDescription
src (required)string—

The image's `src`.

alt (required)string—

The image's alt text; names the placeholder when present.

allowHostsReadonlySet<string> | undefined—

Remote hosts trusted to load on render.

children (required)ReactNode—

The <img> to render once allowed.