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.
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
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "primary" | "secondary" | "ghost" | "quiet" | "danger" | "danger-ghost" | "link" | "secondary" |
|
| size | "xs" | "sm" | "md" | "lg" | "md" | |
| block | boolean | — | |
| truncate | boolean | — | The button may shrink below its label's width; the label then truncates with an ellipsis. |
| wrap | boolean | — | 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. |
| loading | boolean | false | Shows a spinner, keeps the button's width, and blocks interaction. |
| leading | ReactNode | — | Icon rendered before the label. |
| trailing | ReactNode | — | Icon or hint (e.g. <Kbd>) rendered after the label. |
| disabledReason | string | 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.
| Prop | Type | Default | Description |
|---|---|---|---|
| children (required) | string | — | Markdown source. |
| streaming | boolean | false | The text is still arriving: repairs unfinished syntax and only re-renders the last block. |
| measure | boolean | false | Constrain line length to a comfortable ~72ch measure. |
| allowImageHosts | readonly 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. |
| codeActions | CodeBlockActions | 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.
| Prop | Type | Default | Description |
|---|---|---|---|
| src (required) | string | — | The image's `src`. |
| alt (required) | string | — | The image's alt text; names the placeholder when present. |
| allowHosts | ReadonlySet<string> | undefined | — | Remote hosts trusted to load on render. |
| children (required) | ReactNode | — | The <img> to render once allowed. |