Lynx/Modules/Markdown/MarkdownEditor
@sigx/lynx-markdown · Stable · Component library

MarkdownEditor#

True-WYSIWYG markdown editing on the native <sigx-richtext> element. Lightly controlled: markdown in via value, onChange(markdown) out.

Import#

TSX
import { MarkdownEditor } from '@sigx/lynx-markdown/editor';

MarkdownEditor lives on the @sigx/lynx-markdown/editor subpath. Importing the subpath turns the optional peers @sigx/lynx-richtext (the rich-text element — native on iOS/Android, contenteditable on web) and @sigx/lynx-keyboard into real, required dependencies — install both alongside the package.

Basic usage#

value is initial / lightly-controlled — an incoming value equal to the last emitted markdown is treated as the editor's own echo and ignored, so you can safely feed onChange output back in.

TSX
import { MarkdownEditor } from '@sigx/lynx-markdown/editor';

function Composer() {
  return (
    <MarkdownEditor
      value={'# Draft\n\nStart typing…'}
      placeholder="Write something"
      onChange={(markdown) => saveDraft(markdown)}
    />
  );
}

Toolbar#

Pass toolbar to mount the built-in EditorToolbar, or render your own toolbar standalone against the editor's controller.

TSX
<MarkdownEditor value={draft} onChange={save} toolbar />

Mentions and plugins#

Wire createMentionPlugin (or any MarkdownEditorPlugin) through the editor's plugin surface to add parser syntax, document mapping, serialization, and a trigger that opens a SuggestionPopup session.

TSX
import { MarkdownEditor } from '@sigx/lynx-markdown/editor';
import { createMentionPlugin } from '@sigx/lynx-markdown';

const mention = createMentionPlugin({
  trigger: '@',
  debounce: 150,
  search: async (q) => (await searchDirectory(q)).map((p) => ({ id: p.id, label: p.name })),
});

function Composer() {
  return <MarkdownEditor value={draft} onChange={save} plugins={[mention]} toolbar />;
}

Imperative control#

Grab the editor's MarkdownEditorController via controllerRef to drive formatting, insertion, and fullscreen programmatically.

MethodDescription
toggleBold() / toggleItalic() / toggleStrike() / toggleCode()Toggle inline marks on the selection.
setHeading(level)Set the block heading level (06; 0 clears).
setList(kind)'bullet' | 'ordered' | 'task' | 'none'.
toggleQuote()Toggle a blockquote.
insertLink(href, text?) / insertText(text) / replaceRange(start, end, text)Insert or replace content.
insertChip(chip, replace?)Insert a mention/chip span.
clear()Empty the document.
openFullscreen() / closeFullscreen() / isFullscreen()Fullscreen control — restyles the same element in place, never re-parented.

Styling the suggestion popup#

The trigger suggestion popup (mentions, etc.) is themed through the optional suggestionPopup prop — surface/border/active/text colors, plus width/maxHeight/class. Every field is optional, and so is the prop itself: any color you omit auto-tints from the editor's active textColor, so a popup reads as light-on-dark or dark-on-light to match the field without you setting anything. (daisyUI wires concrete theme colors through here via useMarkdownEditorTheme().suggestionPopup, mirroring how textColor/accentColor theme the editor body.) Per-row content stays a plugin concern (trigger.renderItem).

TSX
// Auto-tinted from the dark editor text — no popup colors needed.
<MarkdownEditor value={draft} onChange={save} textColor="#e5e7eb" plugins={[mention]} />

// Or set only the fields you care about; the rest still auto-tint.
<MarkdownEditor value={draft} onChange={save} suggestionPopup={{ width: 280 }} plugins={[mention]} />

Native setup & gotchas#

These apply only to the editor subpath — the renderer needs none of them.

  • SafeAreaProvider for the suggestion popup. The popup's keyboard hook reads keyboard height via @sigx/lynx-keyboard's useKeyboard(), which needs a <SafeAreaProvider> ancestor while the fullscreen overlay is open. Without one it reads height 0 (no crash, no warning).
  • ignore-focus keeps the keyboard up. The toolbar, popup, and fullscreen close affordance carry ignore-focus so taps never blur the editor.
  • Fullscreen restyles in place. Going fullscreen re-styles the same mounted element (a fixed inset overlay); it is never re-parented, which would recreate the native view and lose the document.

Props#

PropTypeDescription
valuestringInitial markdown (lightly-controlled; echoes of the last emitted value are ignored).
onChange(markdown: string) => voidFired with serialized markdown as the document changes.
placeholderstringPlaceholder shown while empty.
minLines / maxLinesnumberLine bounds for the native field.
modeMarkdownEditorModeEditor mode.
toolbarbooleanMount the built-in EditorToolbar.
pluginsMarkdownEditorPlugin[]Trigger/inline plugins (e.g. mentions).
suggestionPopupSuggestionPopupStyleOptional. Style the trigger suggestion popup; omitted colors auto-tint from textColor.
controllerRef(c: MarkdownEditorController) => voidReceives the imperative controller.

See the API reference for the full prop list and the editor-subpath exports (mdToDoc, docToMd, plugin contract types).