Skip to content

Stacking 2+ inline formats on an empty selection renders stray marker characters in the text view (display only — getMarkdown() is correct) #368

@nick87kelly

Description

@nick87kelly

Related: Likely the same root cause as #367 — both stem from the empty "pending format" span created when a format is toggled on an empty selection. In #367 it corrupts the serialized output; here the model/serialization is correct and only the rendered view is wrong.

Environment

  • react-native-enriched-markdown: 0.7.0-nightly-20260529-af2d2f863
  • React Native: 0.81.5 · Expo SDK 54
  • Platform tested: iOS (Expo dev build, simulator). Android not yet tested.

Description

On the first line of an empty document, toggling two or more inline formats with an empty selection and then typing a character renders phantom trailing marker glyphs after the typed text in the on-screen editor. A single format, or typing with no formatting, renders fine. Crucially, the serialized markdown is correct — the phantom characters exist only in the rendered text view, not in the document model.

Steps to reproduce

  1. Render and focus an EnrichedMarkdownTextInput (empty document, first line).
  2. With no selection, call two toggles, e.g. ref.toggleBold(); ref.toggleItalic();.
  3. Type a single character, e.g. D.
  4. Compare the on-screen text against getMarkdown().

Expected

On-screen text shows a styled D only; getMarkdown()"***D***".

Actual

On-screen text shows the styled D followed by stray marker characters (e.g. an extra *). getMarkdown() is correct in every case — the model is fine, only the rendering is wrong. See the attached video: the phantom markers appear on screen while the logged getMarkdown() output stays clean.

On-screen render vs. serialized model

The same toggle+type sequence, comparing what's drawn on screen against getMarkdown(). In every case the typed D is styled correctly and getMarkdown() is valid markdown — only the rendered view appends stray trailing marker glyphs (the leading markers are applied as styling, not shown as text):

Toggled (empty selection) → type D On-screen (styled D + stray trailing) getMarkdown() (model)
Bold + Italic D* ***D***
Bold + Underline D* **_D_**
Bold + Strikethrough D** **~~D~~**
Italic + Underline D* *_D_*
Italic + Strikethrough D* *~~D~~*
Underline + Strikethrough D_ _~~D~~_
Bold + Italic + Underline D** ***_D_***
Bold + Underline + Strikethrough D_** **_~~D~~_**
Italic + Underline + Strikethrough D_* *_~~D~~_*
Bold + Italic + Strikethrough D*** ***~~D~~***

Toggle order does not affect the serialized output (e.g. Italic+Bold, Strikethrough+Bold, and Underline+Strikethrough+Bold produce ***D***, **~~D~~**, and **_~~D~~_** respectively — identical to their counterparts above).

Screen.Recording.2026-06-01.at.4.09.48.PM.mov

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions