Skip to content

DirectWrite text layout cannot resolve font families whose names contain spaces — 'Material Icons' renders tofu, same font renamed 'MaterialIcons' renders #16306

Description

@FaithfulAudio

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.sharedFonts manifest extension land in DirectWrite's per-user system font collection; WPF/DirectWrite enumeration shows the family present under its spaced name (Material Icons), correct cmap/name records.
  • fontFamily: 'Material Icons' → tofu.
  • Same file, family renamed to MaterialIcons (only the OpenType name table 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

  1. Take a TTF whose family name contains a space — e.g. stock MaterialIcons.ttf from react-native-vector-icons (family name Material Icons).
  2. Register it so DirectWrite can see it (we use the windows.sharedFonts package-manifest extension; confirm via any DirectWrite/WPF font enumeration that the family is present).
  3. Render <Text style={{ fontFamily: 'Material Icons' }}>{''}</Text> (any mapped codepoint).
  4. Observe tofu / Segoe UI fallback.
  5. Control: rewrite the font's name table so the family is MaterialIcons (no other change), request fontFamily: '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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs: Triage 🔍New issue that needs to be reviewed by the issue management team (label applied by bot)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions