Repository navigation
Raw HTML in markdown renders as source text on mobile #7929
Description
This issue was written entirely by Fable 5 (running in T3 Code).
What happens
Raw HTML embedded in markdown renders as literal source text on mobile. A README that opens with the common centered-icon header:
<p align="center">
<img src="public/icon-512.png" alt="" width="128" height="128" />
</p>
<h1 align="center">Project Name</h1>shows up in the mobile file preview and thread feed as raw tags. No image element is ever created — this applies to external https: sources too, so it is a rendering capability gap, not a URL-resolution problem.
What #7857 already solves (and deliberately does not)
PR #7857 fixes workspace image URL resolution everywhere images already render: markdown-syntax images () now resolve through signed asset URLs on web and mobile (iOS native renderer and the JS fallback renderer), and web also covers raw HTML <img> because the web pipeline parses HTML. Mobile HTML rendering was explicitly scoped out of that PR as a separate capability.
What to look for
- The native parser already runs with
html: true— HTML arrives ashtml_block/html_inlinenodes carrying raw source text (apps/mobile/modules/t3-markdown-text). Nothing needs to change in the parser or native code. - A tree transform (same pattern as
nativeMarkdownWithPreservedSoftBreaks) that rewrites<img>tags inside those nodes into syntheticimagenodes gets the entire existing image pipeline for free —NativeMarkdownImage, therenderImageoverride, and the signed asset flow from fix(web/mobile): render project images in nested markdown file previews and harden markdown images #7857. The JS fallback can hook the same logic through anhtml_blockentry inCustomRenderers. - Suggested staging: (1)
<img>extraction only (~150–250 lines) — caveat: sibling HTML like the<h1 align="center">still shows as raw text, so blocks render half-fixed; (2) a safe-subset HTML normalizer (p/div/center/h1–h6/a/br/b/i→ equivalent markdown nodes) so HTML-headed READMEs render properly. Stage 2 carries the real design decisions (tag allowlist, attribute degradation likealign, nesting). - No sanitization puzzle on mobile: nothing executes — unknown tags simply remain text, so the allowlist is the safety boundary.
Related: SVG images in mobile markdown
Adjacent gap, worth fixing under this issue's umbrella: SVG sources in mobile markdown render as an empty frame because React Native's <Image> cannot decode SVG (external URLs included — this predates #7857, which deliberately excludes .svg from the signed-asset flow rather than fetch a URL the renderer cannot draw).
- The fix is small (~120–200 lines, no new dependency):
react-native-svgis already installed and exportsSvgUri. Remove the resolver's.svgexclusion, add anSvgUri-based branch in the two renderer hook points (createWorkspaceImageRenderer,createFallbackMarkdownImageRenderer), and passtextStylethrough therenderImagecontract so the SVG frame matches the module's default image frame and caption. - Caveat 1: extension detection covers workspace
.svgfiles but misses the highest-value case — badge URLs (shields.io) usually have no.svgsuffix and only reveal their type via content-type. Covering those needs sniffing or try-SvgUri-first logic; that is real design work beyond the simple version. - Caveat 2:
SvgUrifetches per mount with no cache — fine for file previews, worth attention in the thread feed given repaint/perf sensitivities.
Activity
juliusmarminge commentedon Oct 12, 2026
Note
Grok responding on behalf of Julius.
Resolved by #16979. Mobile now renders Markdown with Enriched Markdown, and raw HTML images and blocks in chat and file previews render as media instead of source text (verified on iOS and Android in that PR). If a specific HTML snippet still shows up raw on a build that includes #16979, comment with it and we'll reopen.