Skip to content

Support custom inline nodes in framework renderers #9

Description

@Stanzilla

Problem

MarkdownExtension.transformInline can transform InlineNode[], but the InlineNode union has no custom component node. The existing ComponentNode is block-only because its children are BlockNode[].

This leaves a gap for inline application UI such as mentions, channels, custom emoji, and embedded assets:

  • an extension can detect and transform the syntax;
  • the HTML renderer has the extension-level renderHtml hook;
  • framework renderers use a closed switch over the built-in inline node types;
  • the React components map can replace emitted tags, but an extension cannot emit a typed custom inline tag.

Consumers must therefore misuse a built-in node such as ImageNode or LinkNode, encode data in sentinel properties, and recover it through the component map. The other option is to replace the framework renderer. The first approach gives non-image or non-link content incorrect semantics; the second loses the benefit of the provided renderer.

Suggested API direction

One option is an inline equivalent of ComponentNode, for example:

interface InlineComponentNode {
  type: 'inlineComponent'
  name: string
  attributes: Record<string, string>
  children: InlineNode[]
  tagName?: string
  properties?: Record<string, string>
}

It could be added to InlineNode and rendered through the existing framework components map, in the same way that block ComponentNode is handled.

Another option is a framework renderer extension hook that can return custom output for an inline node before the built-in renderer handles it.

Example use case

const mentionExtension: MarkdownExtension = {
  name: 'mentions',
  transformInline(nodes) {
    return transformMentions(nodes, mention => ({
      type: 'inlineComponent',
      name: 'mention',
      tagName: 'mention',
      attributes: { id: mention.id },
      children: [{ type: 'text', value: mention.label }],
    }))
  },
}

<Markdown
  extensions={[mentionExtension]}
  components={{ mention: Mention }}
>
  {source}
</Markdown>

The important part is a typed way for transformInline to produce portable custom inline output that React and other framework renderers can render without raw HTML or built-in-node semantic workarounds.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions