Yugen UI

Markdown

Markdown renders content written in Markdown (articles, release notes, CMS fields) with Prose typography, safely for untrusted content.

Pass a Markdown string as children. Supports CommonMark and the common parts of GFM: headings, paragraphs, lists, task lists, quotes, tables, code fences (highlighted by CodeBlock), bold, italic, strikethrough, code and links. No HTML: tags show as text, and javascript: or data: links keep only their label. Relative links (/path, #id) are kept; external links open in a new tab. inline is for one-line text: inline Markdown only, in a <span>. renderLink hands links to the app's router. For text that arrives token by token (AI answers), use StreamingMarkdown.

Getting started with the API

Every request needs an API key in the Authorization header. Create one under Settings.

  1. Create a read-only key.
  2. Store the key in an environment variable.
  3. Try GET /v1/orders.
PlanRequests / min
Free60
Pro1,200

Import

Install from npm, copy the source into your project with @yugen-ui/cli or the shadcn CLI, or import directly when working in this repo.

TSX
// npm install yugen-uiimport { Markdown } from "yugen-ui";

Variants

Each tile is a standalone example: hover to copy, or press Code to see the source.

  • Call sonner.promise to turn loading into the result.
  • HTML from a CMS? See Prose.

Inline

inline renders inline Markdown in a <span>, without a <p>: for list items, table cells, one-line descriptions.

Read the installation guide or Prose. Source code is on GitHub.

Path: /

Links through a router

renderLink gets href, title, the label and external; internal links go through the app's router (router.navigate, the router's <Link to>) instead of reloading the page. The example stands in state for the router.

<img src=x onerror="alert(1)"> and click here

Untrusted content

HTML shows as text and a javascript: link keeps only its label; no need to sanitize first.

Usage

Do
  • Use Markdown for written or CMS content; use StreamingMarkdown for text that arrives token by token.
  • Use inline for one-line text inside another layout (list items, table cells).
  • Turn on headingIds when the page has a table of contents or links to headings.
Don't
  • Don't use Markdown to show HTML from a CMS: the HTML shows as text. Use Prose with sanitized HTML.
  • Don't put Markdown inside Prose: Markdown already wraps itself in Prose.

Props

Prop · TypeDefaultDescription
childrenstringDefault: —Markdown content. No HTML.
inlinebooleanDefault: falseInline Markdown only (bold, italic, strikethrough, code, links) in a <span>, without paragraphs.
size"medium" | "large"Default: "medium"Prose text size: body1 (14px) or body2 (16px).
headingOffsetnumberDefault: 1Added to heading levels: by default # renders as h2.
headingIdsboolean | ((text: string) => string)Default: falseGives headings an id from their text (accents removed, -2, -3 for duplicates); pass a function to make your own ids.
breaksbooleanDefault: falseSingle newlines become <br>.
renderLink(link: MarkdownLink) => ReactNodeDefault: —Renders every link yourself; MarkdownLink has href, title, children and external.

Messages

Text built into the component: labels, aria-labels, screen reader announcements.

English by default. Change it with the messages prop of YugenProvider, by the namespace below; messagesVi has the Vietnamese set. See Interface language.

messages.markdown

Key · TypeDefault (English)messagesVi
newTabstring

Chữ ẩn sau link mở tab mới.

Default (English)"(opens in new tab)"messagesVi"(mở tab mới)"
taskDonestring

Chữ ẩn trước mục danh sách việc đã xong / chưa xong.

Default (English)"Done:"messagesVi"Đã xong:"
taskTodostringDefault (English)"Not done:"messagesVi"Chưa xong:"
tablestring

Tên vùng cuộn của bảng.

Default (English)"Table"messagesVi"Bảng"