Skip to content
Component installs need the registry setup
VegaStack Design

Markdown

Render markdown with MarkdownView and edit it with TextEdit in one typography — every element, slash menu, bubble menu, shortcuts, input rules.

Last updated

Markdown in VegaStack has two surfaces and one typography. MarkdownView renders a markdown string; TextEdit with format="markdown" edits one. Both wear the shared prose recipe from @vegastack/design (proseClassName), and TextEdit resets ProseMirror's defaults, so a document sits at the same position whether it is being read or edited. The recipe is the app's body text — text-sm, the body family and foreground ink for paragraphs, lists, list markers, marks and quotes, headings on the app's type scale — so neither surface has a separate "prose" look. Only inline code and code blocks are mono.

TextEdit is Notion-style: no border, no ground, no focus ring and no view mode. It rests looking exactly like MarkdownView; click anywhere and type. Leaving the editor calls onCommit with the new markdown when it changed; Esc reverts.

import { MarkdownView } from "@/components/ui/markdown-view";
import { TextEdit } from "@/components/ui/text-edit";

// Editable: the editor is the view.
<TextEdit
  format="markdown"
  defaultValue={summary}
  onCommit={save}
  aria-label="Summary"
/>;

// Read-only elsewhere:
<MarkdownView>{summary}</MarkdownView>;

Every element, view and edit

The same document rendered by MarkdownView and edited by a TextEdit, stacked. Headings h1–h6, paragraphs, bold, italic, strike, inline code, fenced code blocks, links, bullet, ordered and task lists (nested), blockquotes, rules, tables, images and hard breaks. Edit the lower copy: the upper one follows.

View

Heading 1

Heading 2

Heading 3

Heading 4

Heading 5
Heading 6

A paragraph with bold, italic, strikethrough, inline code and a link (opens in new tab). A hard line break follows,
then https://example.com (opens in new tab) autolinks in view mode.

  • Bullet item
  • Another item
    • Nested item
  1. First
  2. Second
    1. Nested ordered
  • Done task
  • Open task
    • Nested task

A blockquote carries a quoted thought.

ts
const answer = 42;

NameRole
AdaEngineer
GraceAdmiral

VegaStack mark

Edit
ElementMarkdownNotes
Headings# … ######MarkdownView headingOffset moves them down under a page heading.
Bold / italic**b** / _i_
Strikethrough~~s~~Needs the strike action to edit.
Inline code`c`A muted chip.
Code block```tsThe CodeBlock surface (language and copy) in both modes.
Link[t](url)View mode autolinks bare URLs; external links open a new tab with rel="noopener".
Lists- / 1. Nest with two (bullet) or three (ordered) spaces.
Task list- [ ] / - [x] The system Checkbox is the marker; it toggles in edit mode.
Blockquote>
Rule---
TableGFM pipesScrolls inside its own box.
Image![alt](src)MarkdownView blocks remote origins unless listed in allowedImageOrigins.
Hard breaktrailing \

Slash menu

There is no toolbar. Type / at the start of a line or after a space to open the block menu, then type to filter it. ↑ ↓ move, Enter inserts and

Esc closes it with the text left as typed.

CommandInsertsMarkdown shortcut
Texta plain paragraph
Heading 1–3a heading# ## ###
Bullet lista bullet list-
Numbered listan ordered list1.
Checklista task list[ ]
Quotea blockquote>
Code blocka fenced code block```
Dividera horizontal rule---
Linka link, through the link inputMod K

slashCommands limits and orders the menu, for example a comment composer that offers only lists, code and links. [] turns the menu off. It limits the menu only: markdown typed or pasted for any element still works, so every document round-trips.

A smaller set

Bubble menu

Selecting text floats a small menu with bold, italic, strikethrough, inline code and link. The link button, and Mod K, turn the menu into an inline URL input: Enter applies it, Esc closes it, and Remove unlinks. Pasting a URL over a selection links it directly. Links open in a new tab with rel="noopener noreferrer".

In-place editing

There is no mode to switch. The editor is transparent and borderless, so it takes the surface it sits on and its text lands exactly where MarkdownView would put it. Hover and focus show a faint background tint, never a border or ring, and an empty focused editor hints "Type / for commands". There are no Save or Cancel buttons.

EventResult
Focus leaves the editoronCommit(value) — only when the document differs from when focus came.
EscRevert to the document focus found, blur, then onRevert().
Mod EnteronSubmit(value) when set; otherwise commit and blur.
autosave idle gaponCommit(value) without leaving.

The page going hidden and the editor unmounting mid-edit commit through the same path, so a value is never committed twice. A new value that arrives while the editor is focused waits for blur, so the caret never jumps.

Autosave

autosave also calls onCommit after an idle gap (true is 1000ms, or pass milliseconds). It is off by default.

Not saved yet

Shortcuts

Mod is ⌘ on Apple platforms and Ctrl elsewhere.

KeysAction
Mod BBold
Mod IItalic
Mod KAdd or edit the link
Mod EInline code
Mod Shift SStrikethrough
Mod Alt 2 / 3Heading 2 / 3
Mod Shift 7 / 8 / 9Ordered / bullet / task list
Mod Shift BBlockquote
Mod Alt CCode block
Mod Z / Mod Shift ZUndo / redo
Mod EnterSubmit (onSubmit) or commit
EscRevert (onRevert)
Tab / Shift TabIndent / outdent a list item

Input rules

Type markdown and it becomes formatting as you go. Pasted plain-text markdown is parsed the same way.

TypeBecomes
# … ###### Heading
- or * Bullet list
1. Ordered list
[ ] or [x] Task item
> Blockquote
```Code block
---Divider
**text**Bold
_text_Italic
~~text~~Strikethrough
`text`Inline code

Every rule works in every editor: slashCommands limits the menu, never the schema.

On this page