microsoft / microsoft/react-native-windows
DirectWrite text layout cannot resolve font families whose names contain spaces — 'Material Icons' renders tofu, same font renamed 'MaterialIcons' renders
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 17.3k
- Forks
- 1.2k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 33
Description
Problem Description
On the new architecture, a fontFamily whose name contains a space (e.g. 'Material Icons') fails to resolve even though the font is registered and enumerable in DirectWrite — glyphs render as tofu / fall back to Segoe UI. The identical TTF re-emitted with a space-less family name ('MaterialIcons', name table IDs 1/16 rewritten, glyph outlines untouched) resolves and renders. The space in the requested family name is the only variable.
What we verified empirically (production app):
- Fonts registered via the packaged
windows.sharedFontsmanifest extension land in DirectWrite's per-user system font collection; WPF/DirectWrite enumeration shows the family present under its spaced name (Material Icons), correctcmap/namerecords. fontFamily: 'Material Icons'→ tofu.- Same file, family renamed to
MaterialIcons(only the OpenTypenametable changed) → renders correctly.
Root cause — diagnosed, NOT traced to a specific line (filing for visibility; confidence level stated honestly). The resolution lives in the DirectWrite text-layout path — vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/WindowsTextLayoutManager and/or the font-collection/loader it uses — i.e. how the requested family string reaches CreateTextFormat / FindFamilyName. Plain DirectWrite handles spaced family names fine (Segoe UI is the platform default), so we suspect RNW-side handling of the fontFamily string (tokenizing/trimming, or the custom collection lookup) rather than DirectWrite itself. We could not pin the failing lookup with confidence from a shallow source read, so we did not attempt a patch.
Steps To Reproduce
- Take a TTF whose family name contains a space — e.g. stock
MaterialIcons.ttffromreact-native-vector-icons(family nameMaterial Icons). - Register it so DirectWrite can see it (we use the
windows.sharedFontspackage-manifest extension; confirm via any DirectWrite/WPF font enumeration that the family is present). - Render
<Text style={{ fontFamily: 'Material Icons' }}>{''}</Text>(any mapped codepoint). - Observe tofu / Segoe UI fallback.
- Control: rewrite the font's
nametable so the family isMaterialIcons(no other change), requestfontFamily: 'MaterialIcons'→ glyphs render.
Expected Results
Spaced family names resolve exactly as space-less ones do (and as they do on iOS/Android, and in DirectWrite generally).
CLI version
18.0.0
Environment
System:
OS: Windows 11 10.0.26200 (ARM64 device; app builds and runs ARM64)
CPU: (6) x64 Apple Silicon (Windows-on-ARM)
Memory: 6.49 GB / 15.99 GB
Binaries:
Node: 22.15.0
Yarn: 4.5.1
npm: 10.9.2
SDKs:
Windows SDK versions: 10.0.19041.0, 10.0.22621.0, 10.0.26100.0
IDEs:
Visual Studio: 18.6.11822.322 (Community 2026), 17.14.37314.3 (Community 2022)
npmPackages (yarn 4 workspaces — `cli info` reports Not Found in-workspace):
react-native: 0.83.2
react-native-windows: 0.83.2 (New Architecture / Fabric composition)
Microsoft.WindowsAppSDK: 1.8
Community Modules
react-native-vector-icons 10.3.0 / @expo/vector-icons 15.1.1 are where the spaced-name fonts come from, but the bug is core: it reproduces with any registered TTF whose family name contains a space, rendered through core <Text>.
Target React Native Architecture
New Architecture (WinAppSDK) Only
Target Platform Version
10.0.22621
Visual Studio Version
Visual Studio 2026
Build Configuration
Debug
Snack, code example, screenshot, or link to a repository
Minimal probe is the two-step control above (steps 3 vs 5) — same file, same glyphs, only the family name differs.
Our production workaround: a dependency-free Node script re-emits the Windows copies of all affected fonts with space-less family names (rewriting name IDs 1/16 and recomputing table checksums), registered via windows.sharedFonts; a platform shim makes JS request the space-less names on Windows only.
Related issues: #15316 (umbrella: custom .ttf fontFamily support on new arch), #3463 (old-arch custom-font parity), #15750 (IProvideFontInfo font-loading unification). Related but distinct, filed separately: #16308 — registered stock icon TTFs render blank glyphs until table checksums/table directory are recomputed (loader validation vs. this issue's family-name lookup).
Context: found during a Windows hardening pass of a production RNW app (Facilitron FIT — RNW 0.83.2 new-arch, Windows 11 ARM64, WinAppSDK 1.8, 250% display scale). Sibling PRs from the same investigation: #16302, #16303, #16304. Happy to build a minimal repro repo or test candidate fixes in our app if useful.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/WindowsTextLayoutManager and trace how fontFamily reaches CreateTextFormat or FindFamilyName, including the font-collection or loader path. Reproduce with the registered Material Icons TTF and its space-less control, then verify that spaced family names resolve and render correctly without the workaround.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, react-native
- Domain
- computer-graphics, operating-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100