Skip to main content
Light Dark System

Markdown Editor

<zn-markdown-editor> | ZnMarkdownEditor
Since 1.0 experimental

A markdown editor with live preview, split view, and a fullscreen mode.

zn-markdown-editor wraps the full markdown authoring workflow in a single form control: a textarea for writing, a live preview rendered with marked (bundled with the component), toggleable editor / split / preview modes, a fullscreen toggle, and localStorage persistence for the selected view.

<zn-markdown-editor
  label="Content"
  name="content"
  help-text="Supports GitHub-flavored markdown"
  value="# Hello

Write some **markdown** on the left — use the toolbar to switch to split or preview."
></zn-markdown-editor>

Examples

Initial Value via Attribute

Set the initial markdown with the value attribute.

<zn-markdown-editor
  label="Article"
  name="article"
  value="## Release notes

- New payments dashboard
- Faster settlement reporting"
></zn-markdown-editor>

Initial Value via Light DOM

If no value attribute is set, zn-markdown-editor reads its initial markdown from its own text-node children. This is handy when rendering server-side content into the tag without escaping quotes:

# Terms of Service This copy was rendered from a server-side template and picked up automatically.
<zn-markdown-editor name="content" label="Terms">
# Terms of Service

This copy was rendered from a server-side template and picked up automatically.
</zn-markdown-editor>

Setting the Default View

Use the view-mode attribute to open directly in editor (default), split, or preview.


<zn-markdown-editor
  name="content"
  label="Split by default"
  view-mode="split"
  value="## Split view

See both at once."
></zn-markdown-editor>

<br />

<zn-markdown-editor
  name="content"
  label="Preview by default"
  view-mode="preview"
  value="## Preview view

Toggle to the editor to edit."
></zn-markdown-editor>

Persisting the Selected View

The chosen view mode is persisted in localStorage under the key set by storage-key (default zn-markdown-editor-view-mode). Use distinct keys when multiple editors should remember their own preference.

<zn-markdown-editor
  name="email_template"
  label="Email template"
  storage-key="email-template-view"
></zn-markdown-editor>

To opt out of persistence, set storage-key to an empty string:


<zn-markdown-editor storage-key=""></zn-markdown-editor>

Help Text

Add descriptive help text with the help-text attribute, or use the slot for HTML content.


See the CommonMark cheatsheet for a full syntax reference.
<zn-markdown-editor
  label="Release notes"
  name="notes"
  help-text="Use headings, lists, and code fences for emphasis."
></zn-markdown-editor>

<br />

<zn-markdown-editor label="Release notes" name="notes">
  <div slot="help-text">
    See the <a href="https://commonmark.org/help/">CommonMark cheatsheet</a>
    for a full syntax reference.
  </div>
</zn-markdown-editor>

Rows

Use rows to change the initial height of the editor before it overflows. Default is 20.

<zn-markdown-editor label="Short editor" rows="6"></zn-markdown-editor>

Required, Readonly, Disabled

zn-markdown-editor forwards standard form-control state onto its underlying textarea.



<zn-markdown-editor label="Required" name="content" required></zn-markdown-editor>

<br />

<zn-markdown-editor
  label="Readonly"
  name="content"
  readonly
  value="## Read-only content

Visible but not editable."
></zn-markdown-editor>

<br />

<zn-markdown-editor
  label="Disabled"
  name="content"
  disabled
  value="Disabled editor."
></zn-markdown-editor>

Form Integration

zn-markdown-editor is a form control, so its value is submitted with the surrounding form.


Submit Reset
<form class="markdown-editor-form">
  <zn-markdown-editor
    name="content"
    label="Document"
    required
    value="## Getting started

Write your content here."
  ></zn-markdown-editor>
  <br />
  <zn-button type="submit" color="success">Submit</zn-button>
  <zn-button type="reset" color="secondary">Reset</zn-button>
</form>

<script type="module">
  const form = document.querySelector('.markdown-editor-form');

  await customElements.whenDefined('zn-button');
  await customElements.whenDefined('zn-markdown-editor');

  form.addEventListener('submit', (e) => {
    e.preventDefault();
    const data = Object.fromEntries(new FormData(form));
    alert('Submitted!\n\n' + JSON.stringify(data, null, 2));
  });
</script>

Reacting to Events

Listen for content and view-mode changes.

Events will appear here…
<zn-markdown-editor
  id="event-editor"
  name="content"
  label="Event demo"
  value="Type here..."
></zn-markdown-editor>

<div id="event-log" style="margin-top: 1rem; padding: 1rem; background: var(--zn-color-neutral-100); border-radius: 4px; font-family: monospace; font-size: 0.875rem; max-height: 200px; overflow-y: auto;">
  Events will appear here...
</div>

<script type="module">
  const editor = document.getElementById('event-editor');
  const log = document.getElementById('event-log');

  await customElements.whenDefined('zn-markdown-editor');

  function push(name, detail = '') {
    const t = new Date().toLocaleTimeString();
    log.innerHTML = `[${t}] ${name}${detail ? ': ' + detail : ''}<br>` + log.innerHTML;
  }

  editor.addEventListener('zn-input', () => push('zn-input', `length=${editor.value.length}`));
  editor.addEventListener('zn-change', () => push('zn-change'));
  editor.addEventListener('zn-view-mode-change', (e) => push('zn-view-mode-change', e.detail.mode));
</script>

Programmatic Control

focus(), blur(), checkValidity(), and reportValidity() are all available on the element.


Focus Blur Switch to split Switch to preview Clear
<zn-markdown-editor
  id="control-editor"
  name="content"
  label="Controlled editor"
  value="## Controlled"
></zn-markdown-editor>
<br />
<zn-button id="editor-focus">Focus</zn-button>
<zn-button id="editor-blur">Blur</zn-button>
<zn-button id="editor-split">Switch to split</zn-button>
<zn-button id="editor-preview">Switch to preview</zn-button>
<zn-button id="editor-clear" color="error">Clear</zn-button>

<script type="module">
  const editor = document.getElementById('control-editor');

  await customElements.whenDefined('zn-button');
  await customElements.whenDefined('zn-markdown-editor');

  document.getElementById('editor-focus').addEventListener('click', () => editor.focus());
  document.getElementById('editor-blur').addEventListener('click', () => editor.blur());
  document.getElementById('editor-split').addEventListener('click', () => { editor.viewMode = 'split'; });
  document.getElementById('editor-preview').addEventListener('click', () => { editor.viewMode = 'preview'; });
  document.getElementById('editor-clear').addEventListener('click', () => { editor.value = ''; });
</script>

Fullscreen Mode

Click the fullscreen icon in the top-right to expand the editor to cover its nearest positioned ancestor. Click again to collapse. This is driven by the expanded state on the element, so you can also toggle it programmatically:


<zn-markdown-editor id="fs-editor"></zn-markdown-editor>

<script>
  document.getElementById('fs-editor').expanded = true;
</script>

Events

Event Detail Description
zn-input Fired on every keystroke in the editor.
zn-change Fired when the editor’s value is committed.
zn-view-mode-change { mode: 'editor' | 'split' | 'preview' } Fired when the user switches view modes.

Slots

Slot Description
label Custom HTML label. Alternatively use the label attribute.
help-text Custom HTML help text. Alternatively use the help-text attribute.

CSS Parts

Part Description
base The component’s base wrapper.
toolbar The view-mode / fullscreen toolbar.
editor The textarea wrapper.
preview The rendered markdown preview pane.

Importing

If you’re using the autoloader or the traditional loader, you can ignore this section. Otherwise, feel free to use any of the following snippets to cherry pick this component.

To import this component from the CDN using a script tag:

<script type="module" src="https://cdn.jsdelivr.net/npm/@kubex/zinc@1.0.104/dist/components/markdown-editor/markdown-editor.js"></script>

To import this component from the CDN using a JavaScript import:

import 'https://cdn.jsdelivr.net/npm/@kubex/zinc@1.0.104/dist/components/markdown-editor/markdown-editor.js';

To import this component using a bundler:

import '@kubex/zinc/dist/components/markdown-editor/markdown-editor.js';

Slots

Name Description
label The editor label. Alternatively, use the label attribute.
help-text Help text shown below the editor. Alternatively, use the help-text attribute.

Learn more about using slots.

Properties

Name Description Reflects Type Default
name The name of the control, submitted as part of form data. string ''
value The current markdown content. string ''
defaultValue The default value — used when resetting the form. string ''
label The control’s label. If you need HTML, use the label slot. string ''
helpText
help-text
Help text displayed below the editor. If you need HTML, use the help-text slot. string ''
placeholder Placeholder text shown when the editor is empty. string 'Enter markdown content…'
rows Number of rows for the textarea. number 20
viewMode
view-mode
Which view to show. ViewMode 'editor'
storageKey
storage-key
Key used to persist the selected view mode to localStorage. Set to an empty string to disable persistence. string 'zn-markdown-editor-view-mode'
required Makes the editor required for form submission. boolean false
readonly Makes the editor read-only. boolean false
disabled Disables the editor. boolean false
expanded Whether the editor is currently expanded to cover its containing positioned ancestor. boolean false
updateComplete A read-only promise that resolves when the component has finished updating.

Learn more about attributes and properties.

Events

Name React Event Description Event Detail
zn-view-mode-change Emitted when the user switches between editor / split / preview. CustomEvent
zn-change Emitted when the markdown content changes. -
zn-input Emitted on each keystroke in the editor. -

Learn more about events.

Methods

Name Description Arguments
focus() Sets focus on the editor. options: FocusOptions
blur() Removes focus from the editor. -

Learn more about methods.

Parts

Name Description
base The component’s base wrapper.
toolbar The toolbar containing the view-mode and fullscreen controls.
editor The textarea wrapper.
preview The rendered markdown preview.

Learn more about customizing CSS parts.

Dependencies

This component automatically imports the following dependencies.

  • <zn-button-group>
  • <zn-example>
  • <zn-icon>
  • <zn-textarea>