#8342·tiptap

Markdown hooks cannot access configured extension options

Author: jasonkuhrtCreated Sep 15, 2026Updated Sep 15, 2026
Labelsarea: corearea: markdowncomplexity: mediumimpact: medium

Affected packages

@tiptap/markdown, @tiptap/core

Tiptap Version

3.30.5, reproduced in Node.js through the ESM package exports.

What happened?

parseMarkdown and renderMarkdown cannot access the extension options supplied through .configure(). At runtime, this.options and this.name are undefined. The hook declarations also lack the corresponding this types.

The use case is extension-specific URL handling: configure a URL repair function for parsing and a URL serializer for rendering. These functions need the configured extension's options, without an Editor instance.

Browser Used

Not browser-specific; standalone Node.js.

Reproduction

This deliberately small paragraph extension makes the missing context visible without an editor, browser, or additional extensions:

javascript
import { Node } from '@tiptap/core'
import { MarkdownManager } from '@tiptap/markdown'

const Paragraph = Node.create({
  name: 'paragraph',
  group: 'block',
  content: 'inline*',
  addOptions() {
    return { repairUrl: url => url, serializeMarkdownUrl: url => url }
  },
  parseMarkdown(token, helpers) {
    return helpers.createNode(
      this.name,
      { url: this.options.repairUrl(token.text) },
      helpers.parseInline(token.tokens),
    )
  },
  renderMarkdown(node) {
    return this.options.serializeMarkdownUrl(node.attrs.url)
  },
}).configure({
  repairUrl: url => `https://example.com/${url}`,
  serializeMarkdownUrl: url => `<${url}>`,
})

const manager = new MarkdownManager({ extensions: [Paragraph] })

// Throws: Cannot read properties of undefined (reading 'repairUrl')
manager.parse('asset.png')

// Run independently: throws reading 'serializeMarkdownUrl'.
manager.serialize([{
  type: 'paragraph',
  attrs: { url: 'https://example.com/asset.png' },
  content: [{ type: 'text', text: 'asset.png' }],
}])

Expected behavior

Parsing should return:

javascript
{
  type: 'doc',
  content: [{
    type: 'paragraph',
    attrs: { url: 'https://example.com/asset.png' },
    content: [{ type: 'text', text: 'asset.png' }],
  }],
}

Serialization should return <https://example.com/asset.png>.

Additional context

MarkdownManager.registerExtension resolves both hooks without supplying the extension context. The manager already has the configured extension, so accessing its options should not require an Editor.

A local package patch passes focused ESM checks for configured function options, chained configuration, independent instances, and hooks calling their parent.