Skip to content

Feature request: opt-in literal text mode for custom tag children (allowedTags) #419

@songkeys

Description

@songkeys

Summary

Please add an opt-in way to render children of selected custom tags as plain text (no markdown parsing).

Motivation

In AI UIs, custom tags are often used for structured entities such as mentions:

<mention user_id="123">@_some_username_</mention>

Today, markdown in tag children is still parsed, so _some_username_ can become italics.

For entity tags (usernames/handles/IDs), this is often unintended.

Current Behavior

With allowedTags + components, child text is parsed as markdown (expected CommonMark/react-markdown behavior), e.g.:

  • _some text_ -> emphasis
  • @_foo_ -> emphasis in handle-like content

This happens even with parseIncompleteMarkdown={false} (because this is normal markdown parsing, not remend completion).

Why this matters

For mention/entity tags, children are usually data labels, not prose. Requiring model-side escaping (\\_) everywhere is fragile and adds prompt/runtime complexity.

Minimal Repro

import { Streamdown } from 'streamdown';

function Mention(props: any) {
  return <span data-tag="mention" {...props} />;
}

<Streamdown
  allowedTags={{ mention: ['user_id'] }}
  components={{ mention: Mention }}
>
  {`<mention user_id="123">_some text_</mention>`}
</Streamdown>

Actual output renders emphasis inside mention content.
Desired output is literal _some text_.

Requested API (non-breaking, opt-in)

Any equivalent API would help, for example:

<Streamdown
  allowedTags={{ mention: ['user_id'] }}
  literalTagContent={['mention']}
/>

or per-tag config:

allowedTags={{
  mention: { attributes: ['user_id'], literalChildren: true }
}}

Expected semantics for literal mode

  1. Children text for specified tags is treated as plain text.
  2. Markdown emphasis/link/code parsing is skipped for those children.
  3. Default behavior remains unchanged for all other tags and users.

Workaround today

Escaping underscores (\\_) works, but is brittle for AI-generated content and requires extra sanitization logic in app code.

An official opt-in mode would make mention/entity rendering much more robust.

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