Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Markdown Formatting Command Menu Block for React

A notes editor's formatting menu shown open over a note: a real textarea with a sample sits above seven rows that format its selection or insert a block, and a preview and a mono line show the result.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Format text from the keyboard and watch the markdown change with this markdown formatting command menu for React with Base UI. It opens from a note in Scribbleloft, a notes editor, whose header holds an outline field with its ⌘ K cap, and the note is drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The menu is the catalog Command with a band at its top: a real Textarea holding a sample, editable and keeping its selection when focus moves into the list, beside a preview built from it. Seven rows act on that text with plain functions of the text and the selection: Bold wraps the selection in ** and unwraps it again, Link wraps it as [text](url) and selects the address, Heading cycles ##, ### and none on the line, Bullet list toggles - on every line the selection touches, and Table, Divider and a Meeting-note template go in under the line. Enter applies the row and the menu stays open, so several can be applied in a row; the selection moves to what changed, a mono line shows the markdown that was written, and the drawn page behind the menu mirrors the note. For preview the menu is drawn open in place when the page loads; the field, or Ctrl or ⌘ K while focus is in the block, opens the real command dialog with the same text and query. For notes, docs and comment editors.

FAQ

Why is the menu already open, and what do I keep?

So you can see it without a click. On load the menu is the Command and its sample band drawn inline under a picture of the note, in a plain shell that is not modal, so nothing is trapped, hidden or focused and the page around the preview keeps working. The header's field opens the real command dialog, modal, with its focus trap, Escape and focus return, and the inline copy stays closed until a reload. Both show the same Palette and share the block's state, so the text you edited in the copy is the text the dialog opens with. In your app keep the dialog and drop the copy: the "in-place" state, the scrim with its shell and the Escape and blur effects.

How does an action know what is selected?

It asks the Textarea. The browser keeps a textarea's selection after focus leaves it, so choosing a row in the list still sees the words you selected; the block reads selectionStart and selectionEnd when the row is chosen and passes them, with the text, to a pure function that returns the new text and where the selection goes. After the action the selection is put on what changed without moving focus, so Bold can be pressed again to unwrap, and the text you typed around the selection is never touched.

What does each row do?

Heading cycles the line through ##, ### and plain. Bold wraps the selection in **, unwraps it if it is already wrapped (inside or just around the selection), and with nothing selected puts a **bold** placeholder in with the word selected. Link wraps the selection as [text](https://example.com) and leaves the address selected for you to type over. Bullet list starts each line the selection touches with - or takes the bullets off if every line has one. Table, Divider and Meeting-note put a block in under the line after a blank line and select it, so it is easy to see where it landed.

How is the preview made, and is it safe?

From typed pieces, never from HTML: the text is cut into headings, list items, rules, tables and paragraphs, and each line into plain, bold and link pieces that are drawn as elements. A link is drawn underlined and opens nothing. Because nothing is parsed into markup there is nothing to inject, which is also why it handles only the small subset the menu writes; in your app use the renderer your editor already has.

What stays local, and how do I wire it?

All of it. The sample and the preview are state in the block, nothing is saved or sent, and nothing touches the clipboard. In your app give the band's Textarea your document's text or the editor's selection, and have each editFor result go through your editor's own transaction so undo and collaboration keep working.

Is it accessible from the keyboard?

Yes. Type to search the actions, the arrow keys move through them, Enter applies, and Escape closes the menu and puts focus on the field; Tab reaches the sample. Ctrl or ⌘ K opens the dialog while focus is inside the block, and only then. The rows are options of a cmdk listbox; the block turns off its own fuzzy filter and lists the rows itself. The icons are hidden from assistive technology; each row is read as its name and what it does, and each action is announced on the status line.

  • Pro

    A code editor's snippet library as a command menu shown open over the editor: a language switch, a pane that follows the highlighted snippet with highlighted code and Copy, and Enter inserts it into the buffer.

  • Pro

    A help desk's reply library as a command menu shown open over a ticket: choosing a reply with slots turns the menu into a short form, a textarea previews the filled reply, and Enter inserts it.

  • Pro

    A support inbox's quick edit as a command menu shown open under a ticket's header: pick a field, edit it in the right control, see Before and After, and Enter saves into the record card.

  • Pro

    A team chat's emoji menu shown open over its composer: names and shortcodes, a skin-tone switch for hands and people, and Enter adds an emoji to the message under the list while the menu stays open.

  • Pro

    An editor extension's quick fixes as a command menu shown open over the editor: a small code view with flagged lines and numbered line buttons, and a list of only the fixes that apply to the chosen line.

  • Pro

    Basic Command Menu

    Search everything

    A team workspace's home page with its command menu shown open: eleven pages in three groups, a shortcut on the five most used, matches marked, an empty state that says what to try and a foot with the key hints and a spoken count.