Examples › Track 2 — Bidirectional › Example 6

Reverse fence handlers

A fence plugin with render alone is forward-only — once the fence is rendered to HTML, the source is lost. Add a reverse(node) handler and the fence round-trips through quikdown_bd safely. Below: a custom quote fence that round-trips.

Live three-pane round-trip

1. Source

2. Rendered (editable)

3. Markdown back


          

The plugin

const quoteFencePlugin = {
  // Forward: render the fence to HTML.
  // Stash the original source on data-qd-source so reverse() can find it.
  render(content, lang) {
    if (lang !== 'quote') return undefined;
    const escaped = content.replace(/"/g, '"');
    return `<blockquote class="quote-card" data-qd-fence="\`\`\`" data-qd-lang="quote" data-qd-source="${escaped}">` +
      content.trim() +
      `</blockquote>`;
  },

  // Reverse: read the source attribute and reconstruct the fence.
  reverse(node) {
    if (!node.classList?.contains('quote-card')) return null;
    const source = node.getAttribute('data-qd-source') || node.textContent;
    return { fence: '\`\`\`', lang: 'quote', content: source };
  }
};

// Use it on both forward and reverse calls — same plugin object.
const html = quikdown_bd(md, { fence_plugin: quoteFencePlugin });
const md2  = quikdown_bd.toMarkdown(htmlOrEl, { fence_plugin: quoteFencePlugin });