You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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 as html_block / html_inline nodes 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 synthetic image nodes gets the entire existing image pipeline for free — NativeMarkdownImage, the renderImage override, and the signed asset flow from fix(web/mobile): render project images in file markdown previews and harden markdown images #7857. The JS fallback can hook the same logic through an html_block entry in CustomRenderers.
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 like align, 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-svg is already installed and exports SvgUri. Remove the resolver's .svg exclusion, add an SvgUri-based branch in the two renderer hook points (createWorkspaceImageRenderer, createFallbackMarkdownImageRenderer), and pass textStyle through the renderImage contract so the SVG frame matches the module's default image frame and caption.
Caveat 1: extension detection covers workspace .svg files but misses the highest-value case — badge URLs (shields.io) usually have no .svg suffix 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: SvgUri fetches per mount with no cache — fine for file previews, worth attention in the thread feed given repaint/perf sensitivities.
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:
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
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.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 file markdown previews and harden markdown images #7857. The JS fallback can hook the same logic through anhtml_blockentry inCustomRenderers.<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).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.svgfrom the signed-asset flow rather than fetch a URL the renderer cannot draw).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..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.SvgUrifetches per mount with no cache — fine for file previews, worth attention in the thread feed given repaint/perf sensitivities.