Skip to content

HyMarkdownEditor ​

Usage examples on this page are written for Lit / plain HTML (<hy-markdown-editor>). The same component ships as HyMarkdownEditor in @whitespaceux/harmony-react (native React 19), with typed wrappers for Angular, Solid, Svelte, and Vue. The API reference below applies to all frameworks.

Markdown editor with a CodeMirror 6 source pane and a unified-pipeline preview, presented either as a single pane with a Source ⇄ Preview toggle or as a side-by-side split.

The view prop picks the layout strategy. The default view="single" shows one pane with a Source ⇄ Preview eye toggle. view="auto" makes it responsive — a container query renders source + preview side-by-side when the editor is wide and collapses back to the single-pane toggle when it is narrow. view="split" pins the side-by-side layout with a draggable hy-splitter handle so the panes can be resized. In any split layout the preview refreshes live (debounced) as you type.

Fenced code in the preview is syntax-highlighted for css, diff, html, javascript (js), json, jsonc, jsx, markdown (md), scss, shellscript (bash, sh), svelte, tsx, typescript (ts), vue and yaml (yml), in a light / dark theme pair. The highlighter and each language's grammar load the first time a document uses them, so prose costs nothing extra; a fence in any other language, or none, renders as plain code.

When to use

  • Long text that needs headings, lists, links or emphasis: a description, notes, documentation.
  • Writing that people want to check as it will look, with the preview.

Do

  • Set maxlength when the text has a limit, and say the limit beside the field.

When not to use

  • A short plain value such as a name: hy-text-input. Several lines of plain text: hy-text-area.
  • Showing stored markdown without editing it: render it as HTML on the page. Use readonly only when the source itself must stay visible.
  • Files that are not part of the text: hy-file-upload.

Examples ​

Basic (single pane with Source ⇄ Preview toggle) ​

html
<hy-markdown-editor label="Description" placeholder="Type Markdown..."></hy-markdown-editor>

Responsive (auto split when wide, eye toggle when narrow) ​

html
<hy-markdown-editor view="auto" label="Notes" value="# Live preview"></hy-markdown-editor>

Pinned side-by-side split ​

html
<hy-markdown-editor view="split" label="Notes" value="# Live preview"></hy-markdown-editor>

Mode-locked preview ​

html
<hy-markdown-editor mode="preview" no-mode-toggle value="# Hello"></hy-markdown-editor>

Autofocus inside a dialog (overlay-discovery contract) ​

html
<hy-dialog>
  <hy-markdown-editor autofocus autoselect value="# Existing"></hy-markdown-editor>
</hy-dialog>

API ​

Properties ​

PropertyAttributeTypeDefaultDescription
editorView—EditorView | null—Access the live CM6 view. Public for tests / advanced consumers (e.g. wiring custom keymap extensions). Returns null before the widget has mounted (SSR, pre-firstUpdated).
uniqueIdunique-idstring''—
valuevaluestring''—
modemode'source' | 'preview''source'—
viewview'auto' | 'single' | 'split''single'Pane layout strategy — single (default) | auto | split. Reflected so the container-query split rules in the stylesheet can branch on it. See MarkdownEditorView. The mode toggle still governs which pane shows in single-pane layouts; in a split layout both panes are visible and the toggle is hidden.
noModeToggleno-mode-togglebooleanfalse—
placeholderplaceholderstring''—
labellabelstring''—
disableddisabledbooleanfalse—
autofocusautofocusbooleanfalseFocus the source pane on first connect. This is primarily the marker overlay containers (dialog, drawer, popover) discover on show; secondarily a page-load focus shortcut with the same UX caveats as native HTML autofocus.
autoselectautoselectbooleanfalsePre-select the source-pane contents after autofocus (or after .focus() followed by .select()). Mirrors text-area / text-input.
namenamestring''Form-field name. Set when the editor participates in a <form>.
requiredrequiredbooleanfalseMarks the editor as required for form validation.
readonlyreadonlybooleanfalseRead-only: source pane is non-editable but still focusable. The format tools stay in place — inert, out of the accessibility tree and painted quiet — so the editor keeps its shape; the mode toggle keeps working.
spellcheckspellcheckbooleantrueOverride the default spellcheck="true" on the source pane. Note this shadows the inherited HTMLElement.spellcheck boolean — the inner textarea reads from this property only.
maxlengthmaxlengthnumber | nullnullMaximum character length of the markdown source.
minlengthminlengthnumber | nullnullMinimum character length of the markdown source.
uploadImage—ImageUploadHandler | undefined—Host-provided async upload hook. When set, the image dialog gains a drop/pick upload affordance (an embedded hy-file-upload); the host wires this to its asset store (e.g. Supabase Storage behind the Clerk session). When absent, the image dialog is URL-only. Library-side property, not an attribute — the consuming app injects the function.
acceptedImageTypesaccepted-image-typesstring'image/*'accept filter forwarded to the embedded hy-file-upload. Defaults to image/*.
maxImageBytesmax-image-bytesnumber | nullnullMax upload size in bytes, forwarded to hy-file-upload's max-size.
strings—Partial<MarkdownEditorStrings>{}The editor's built-in strings (toolbar labels, heading menu, mode toggle and announcements, pane names, insert-image dialog, upload error). Set the keys you translate; the rest keep their English defaults (DEFAULT_MARKDOWN_EDITOR_STRINGS). A JS property, not an attribute. Use for internationalization.
imageUploadStrings—Partial<FileUploadStrings>{}The built-in strings of the image dialog's upload zone (call to action, drop line, accepted types, progress, remove buttons, rejection messages), forwarded to the embedded `hy-file-upload`'s `strings`. Set the keys you translate; the rest keep their English defaults (`DEFAULT_FILE_UPLOAD_STRINGS`). A JS property, not an attribute. Use for internationalization.

Events ​

EventDetailDescription
input—Detail { value: string }. Fired on every keystroke.
change—Detail { value: string }. Fired on blur after the value changed.
mode-change—Detail { mode, previous }. Fired when the mode-toggle button is clicked. Not fired for programmatic el.mode = ... assignment.
image-upload-start—Detail { file: File }. Fired when a picked/dropped image starts uploading via the uploadImage callback.
image-upload-error—Detail { file: File, message: string }. Fired when the uploadImage callback rejects.

Slots ​

SlotDescription
extra-toolsExtra toolbar items, rendered in the toolbar's trailing cluster next to the mode toggle. Use for primary actions anchored to the editing surface (e.g. Save / Cancel on an editable document). Only visible while the toolbar is — source / split mode; hidden in single-pane preview. React mirror: the extraTools prop.

CSS Parts ​

PartDescription
baseOuter wrapper.
toolbarTop bar holding the formatting controls and mode toggle.
format-toolsLeading group of formatting controls (source mode only).
mode-toggleThe Source ⇄ Preview toggle button.
bodyThe editing / preview surface.
sourceThe source pane (CodeMirror 6 mount).
previewThe preview pane.
preview-skeletonLoading placeholder shown while the cold preview pipeline loads.
live-regionScreen-reader announcement region for mode pivots.
image-dialogThe insert-image dialog (hy-dialog).

CSS Custom Properties ​

The documented hooks. Every override hook the component reads — one per token it paints — is listed in @whitespaceux/harmony/theme-api.json, and @whitespaceux/harmony/component-bindings.json (the Harmony MCP get-bindings tool) says which part and state each one paints.

PropertyDefaultDescription
--hy-markdown-editor-min-height—Minimum height of the body. Defaults to 12rem.
--hy-markdown-editor-padding-form-mdvar(--hy-padding-form-md)Vertical padding inside source / preview.
--hy-markdown-editor-padding-layout-lgvar(--hy-padding-layout-lg)Horizontal padding inside source / preview.
--hy-markdown-editor-padding-form-smvar(--hy-padding-form-sm)Vertical padding inside the toolbar.
--hy-markdown-editor-icon-size-lgvar(--hy-icon-size-lg)Height of the vertical toolbar separator.
--hy-markdown-editor-gap-form-smvar(--hy-gap-form-sm)Gap between toolbar items.
--hy-markdown-editor-radius-form-mdvar(--hy-radius-form-md)Border radius of the outer wrapper.
--hy-markdown-editor-stroke-smvar(--hy-stroke-sm)Border width.
--hy-markdown-editor-border-default-restvar(--hy-border-default-rest)Border color.
--hy-markdown-editor-background-surface-basevar(--hy-background-surface-base)Background color.
--hy-markdown-editor-foreground-default-restvar(--hy-foreground-default-rest)Foreground / text color.
--hy-markdown-editor-tools-foreground-faint-restvar(--hy-foreground-faint-rest)Format tool glyph color while readonly
--hy-markdown-editor-placeholder-foreground-subtle-restvar(--hy-foreground-subtle-rest)Color of the source field's placeholder.
--hy-markdown-editor-code-sm-font-familyvar(--hy-code-sm-font-family)Source-pane font family.

Methods ​

focus() ​

Focus the CM6 editor. No-op when the source pane can't be shown (single-pane preview) or before mount.

select() ​

Select the entire source-pane content. No-op when the source pane can't be shown.

Built with Lit. Documented with VitePress.