Skip to content

iOS Fabric: fontFamily (PostScript name) + explicit fontWeight resolves to the heaviest face — elvis-operator typo in RCTFontUtils.mm #58176

Description

@pdbaker10

Description

On iOS/Fabric in React Native 0.86.2, any <Text> style that combines a PostScript-named fontFamily with an explicit non-default fontWeight renders the heaviest face in the family instead of the requested weight.

// Renders Poppins-Medium (correct)
<Text style={{ fontFamily: 'Poppins-Medium' }} />

// Renders Poppins-Bold (bug — expected Poppins-Medium)
<Text style={{ fontFamily: 'Poppins-Medium', fontWeight: '500' }} />

// Renders Poppins-Bold (bug — expected Poppins-SemiBold)
<Text style={{ fontFamily: 'Poppins-SemiBold', fontWeight: '600' }} />

// Bare family name + weight resolves correctly (different code path)
<Text style={{ fontFamily: 'Poppins', fontWeight: '500' }} />  // correct

Verified via the rendered NSAttributedString font runs (not UIFont lookups): the fonts are registered and loadable; the resolver selects the wrong face.

Root cause

ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTFontUtils.mm (~line 364):

fontWeight = (fontWeight != 0.0) ?: RCTGetFontWeight(font);

The GNU ?: (elvis) operator assigns the boolean result of the comparison — 1.0 — for any explicit nonzero weight, rather than preserving the original fontWeight value. UIFontWeight 1.0 is the heaviest weight, so the subsequent family search selects the boldest face.

Suggested fix

fontWeight = (fontWeight != 0.0) ? fontWeight : RCTGetFontWeight(font);

(Note: this still cannot distinguish an explicit fontWeight: '400' from "no weight," since UIFontWeightRegular == 0.0 — a separate, pre-existing limitation.)

Impact

Any app pairing custom-font PostScript names with explicit weights (a common pattern, and the style many older codebases carry from pre-Fabric versions where the named face won) renders bold text across the board after upgrading. We hit this migrating a production app from 0.81.5 to 0.86.2 — every fontFamily: 'Poppins-<Face>' + matching fontWeight pair (~450 style sites) collapsed to Poppins-Bold. We are carrying a one-line patch-package fix of the ternary, which restores correct resolution for all pairings.

Steps to reproduce

  1. Bundle a multi-weight custom font family (e.g. Poppins Regular/Medium/SemiBold/Bold) via UIAppFonts.
  2. Render <Text style={{ fontFamily: 'Poppins-Medium', fontWeight: '500' }}>test</Text> on 0.86.2 with Fabric.
  3. Inspect the rendered attributed string: the resolved font is Poppins-Bold.

Environment

React Native 0.86.2 (Fabric / new architecture), iOS 26.5 simulator + device, Expo SDK 57 prebuild (bare workflow equivalent). Regression vs 0.81.5 behavior.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs: Author FeedbackNeeds: ReproThis issue could be improved with a clear list of steps to reproduce the issue.StaleThere has been a lack of activity on this issue and it may be closed soon.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions