Skip to content

fix(theme): keep font weights with the System family on Android - #1930

Open
bataevvlad wants to merge 2 commits into
masterfrom
fix/android-system-font-weight
Open

bataevvlad wants to merge 2 commits into
masterfrom
fix/android-system-font-weight

Conversation

@bataevvlad

@bataevvlad bataevvlad commented Sep 28, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

On Android every text with weight 500 or 600 renders regular: s1 / s2 subtitles, labels, radio and checkbox text, the Avatar initials from #1926. iOS shows them semibold.

The Eva and Material mappings set text-font-family: "System". React Native Android does not treat System as the platform font: any fontFamily name goes through ReactFontManager.getTypeface, which looks up the family by nearestStyle (only regular or bold, weight < 700 -> regular) and falls back to Typeface.create(name, style). The numeric weight is only kept when fontFamily is unset (ReactTypefaceUtils.applyStyles, typefaceStyle.apply(Typeface.DEFAULT)). So 600 became 400, while 700+ still looked bold.

This is a different cause from #1793 (custom fonts registered with only a regular face), which stays documented in the branding guide.

Fix

  • New internal theme/style/platformFontFamily.ts: resolvePlatformFontFamily(key, value, os = Platform.OS) resolves a *fontFamily value of System to undefined on Android. StyleService.createThemedEntry (every mapping and StyleService.create style goes through it) calls it. The key stays, so a later consumer style still overrides as before; iOS and custom families are unchanged.
  • FalsyText's fast path checks that the style has a fontFamily key instead of a defined value, so the Android text keeps skipping the extra styled Text.
  • Branding guide: a paragraph under "Font weights on Android".

Verification

  • Specs: platformFontFamily.spec.ts covers the rule as a pure function (Android drops System for *fontFamily keys; iOS / web keep it; custom families, non-font keys and non-string values pass through), without redefining Platform.OS. style.spec.tsx checks createThemedEntry keeps System under Jest's iOS platform. On master the Android case renders System.
  • Android emulator (Pixel 7, API 34), showcase RadioGroup / Card: option labels and "Card presses" render semibold like iOS; regular on master. Screenshots master vs branch.
  • iOS simulator (iPhone 17): same sections, no visual change against master.
  • Gates: yarn test --runInBand (75 suites, 1892 tests), turbo build components, yarn typecheck:all, lint (0 errors).

Changeset: @ui-kitten/components patch.

React Native Android treats any fontFamily as a custom family and rounds
fontWeight to regular or bold, so 500/600 text with the default System
family rendered regular. Resolve System to no family on Android so the
platform font keeps the numeric weight; iOS and custom families are
unchanged.
resolvePlatformFontFamily takes the platform as a parameter, so its
spec covers Android and iOS without redefining Platform.OS for the
whole suite. StyleService.createThemedEntry calls it.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant