[0.73.1] fontWeight not apply while using custom font
Description
I just tried to use custom font in my project template, and i realize when i want to use fontWeight as a reference of my custom font family it's not applicable, is it expected or am i doing something wrong while linking my custom font?
I'm expecting fontWeight should applicable with font as google fonts declared
- Thin 100
- Thin 100 Italic
- ExtraLight 200
- ...
Steps to reproduce
- Download font from google
- Extract downloaded font and copy font into project directory (without
ptprefix) - linking the fonts with react-native-asset
- Paste this code in
App.[js/tsx]
import React from 'react';
import { Text, View } from 'react-native';
const TextExample = props => {
const fontListRegularWithFontWeight = [
{fontFamily: 'DMSans-Regular', fontWeight: '100'},
{fontFamily: 'DMSans-Regular', fontWeight: '200'},
{fontFamily: 'DMSans-Regular', fontWeight: '300'},
{fontFamily: 'DMSans-Regular', fontWeight: '400'},
{fontFamily: 'DMSans-Regular', fontWeight: '500'},
{fontFamily: 'DMSans-Regular', fontWeight: '600'},
{fontFamily: 'DMSans-Regular', fontWeight: '700'},
{fontFamily: 'DMSans-Regular', fontWeight: '800'},
{fontFamily: 'DMSans-Regular', fontWeight: '900'},
];
const fontListWithCustomFontOnly = [
{fontFamily: 'DMSans-Thin'},
{fontFamily: 'DMSans-ExtraLight'},
{fontFamily: 'DMSans-Light'},
{fontFamily: 'DMSans-Regular'},
{fontFamily: 'DMSans-Medium'},
{fontFamily: 'DMSans-SemiBold'},
{fontFamily: 'DMSans-Bold'},
{fontFamily: 'DMSans-ExtraBold'},
{fontFamily: 'DMSans-Black'},
];
return (
<View style={{flex: 1}}>
<Text style={{textAlign: 'center'}}>Custom Font Regular with fontWeight</Text>
<View style={{borderWidth: 1, margin: 14, padding: 14, marginBottom: 24, alignItems: 'center'}}>
{fontListRegularWithFontWeight.map((x, i) => (
<Text key={x.fontFamily + i} style={x}>
{JSON.stringify(x)}
</Text>
))}
</View>
<Text style={{textAlign: 'center'}}>Custom Font With Exact Font Name</Text>
<View style={{borderWidth: 1, margin: 14, padding: 14, alignItems: 'center'}}>
{fontListWithCustomFontOnly.map((x, i) => (
<Text key={x.fontFamily + i} style={x}>
{JSON.stringify(x)}
</Text>
))}
</View>
</View>
);
};
export default TextExample;
React Native Version
0.73.1
Affected Platforms
Runtime - Android
Output of npx react-native info
info Fetching system and libraries information...
System:
OS: macOS 12.5
CPU: (8) x64 Intel(R) Core(TM) i5-1038NG7 CPU @ 2.00GHz
Memory: 679.42 MB / 16.00 GB
Shell:
version: 5.8.1
path: /bin/zsh
Binaries:
Node:
version: 18.19.0
path: /usr/local/bin/node
Yarn:
version: 1.22.19
path: ~/.yarn/bin/yarn
npm:
version: 10.2.3
path: /usr/local/bin/npm
Watchman:
version: 2023.12.04.00
path: /usr/local/bin/watchman
Managers:
CocoaPods: Not Found
SDKs:
iOS SDK:
Platforms:
- DriverKit 21.4
- iOS 16.0
- macOS 12.3
- tvOS 16.0
- watchOS 9.0
Android SDK:
API Levels:
- "27"
- "28"
- "29"
- "30"
- "31"
- "33"
- "34"
Build Tools:
- 28.0.3
- 29.0.2
- 29.0.3
- 30.0.2
- 30.0.3
- 31.0.0
- 33.0.0
- 33.0.1
- 33.0.2
- 34.0.0
System Images:
- android-23 | Intel x86 Atom_64
- android-27 | Google APIs ARM 64 v8a
- android-28 | Google APIs Intel x86 Atom
- android-29 | Google APIs Intel x86 Atom
- android-30 | Google APIs Intel x86 Atom
- android-30 | Google Play ARM 64 v8a
- android-34 | Google APIs Intel x86_64 Atom
Android NDK: Not Found
IDEs:
Android Studio: 2022.3 AI-223.8836.35.2231.10406996
Xcode:
version: 14.0.1/14A400
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.9
path: /usr/bin/javac
Ruby:
version: 2.7.4
path: /Users/administrator_1/.rvm/rubies/ruby-2.7.4/bin/ruby
npmPackages:
"@react-native-community/cli": Not Found
react:
installed: 18.2.0
wanted: 18.2.0
react-native:
installed: 0.73.1
wanted: 0.73.1
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: Not found
newArchEnabled: false
### Stacktrace or Logs
```text
noneed
Reproducer
https://snack.expo.dev/w667bnl74
Screenshots and Videos
Use fontFamily name instead of fontWeight
ex : use FamilyName-Medium instead of familyName + 500
@Linuhusainnk I'm not asking how to use it, I'm asking why fontWeight is not apply when using custom font? the font itself support all fontWeight from 100-900
Please check below things are done properly
- iOS -> Info Plist
- Android > SRC > MAIN > ASSETS > FONTS > all files are placed.
- Styles must have fontFamily : "FontName-FontWeightName , e.g. fontFamily : "FiraSans-Regular"
and to answer your question please check https://github.com/facebook/react-native/issues/26193
As far as I have understood, this issue has unfortunately existed for years for Android.
Here's a great workaround of how you can make the fontWeight property work properly by utilising Android's XML font feature. Note that this workaround doesn't work with EXPO without ejecting.
Stack overflow answer: https://stackoverflow.com/a/70247374 Step-by-step guide: https://github.com/jsamr/react-native-font-demo
Use fontFamily name instead of fontWeight
ex : use FamilyName-Medium instead of familyName + 500
I use this workaround
function mapFontweightToFontFamily(weight: FontWeight, fontPrefix = "Mulish") {
switch (weight) {
case "extralight":
return `${fontPrefix}ExtraLight`;
case "light":
return `${fontPrefix}Light`;
case "regular":
return `${fontPrefix}`;
case "semibold":
return `${fontPrefix}SemiBold`;
case "bold":
return `${fontPrefix}Bold`;
case "extrabold":
return `${fontPrefix}ExtraBold`;
case "black":
return `${fontPrefix}Black`;
default:
return `${fontPrefix}`;
}
}
Do you still experience this issue? If yes, I will publish the fix in the react-native-improved package https://github.com/fabriziobertoglio1987/react-native-improved. Thanks a lot
I can confirm that I am also running into this issue and the problem with the proposed workaround is that you need to add these font files to your app which wouldn't be needed when using fontWeight.
@fabriziobertoglio1987 yes, the issue still persist.
i don't really understand why we need react-native-improved to fix this issue, is it not possible to fix into react-native core, so you need to create a patch to support fontWeight with custom font? or the patch itself is a temporary solution while we waiting RN Team fixed the issue?
i think it should be fixed in react-native source, since Text itself is a part of react-native core component.
@fabOnReact @cortinico can we override the ReactTypefaceUtils.java to something like this ?
ReactTypefaceUtils.java Based on 0.73.1:
ReactTypefaceUtils [CHANGES]
--- com/facebook/react/views/text/ReactTypefaceUtils.java
+++ com/facebook/react/views/text/ReactTypefaceUtils.java
@@ -179,6 +179,35 @@
return TextUtils.join(", ", features);
}
+ public static String FontFamilyMappingWithWeight(String fontFamilyName, int fontWeight){
+ if(fontFamilyName.toLowerCase().contains("regular") && fontWeight > 0){
+ String extractFontFamily = fontFamilyName.split("-")[0];
+
+ switch (fontWeight) {
+ case 100:
+ return extractFontFamily+"-Thin";
+ case 200:
+ return extractFontFamily+"-ExtraLight";
+ case 300:
+ return extractFontFamily+"-Light";
+ case 400:
+ return extractFontFamily+"-Regular";
+ case 500:
+ return extractFontFamily+"-Medium";
+ case 600:
+ return extractFontFamily+"-SemiBold";
+ case 700:
+ return extractFontFamily+"-Bold";
+ case 800:
+ return extractFontFamily+"-ExtraBold";
+ case 900:
+ return extractFontFamily+"-Black";
+ }
+ }
+
+ return fontFamilyName;
+ }
+
public static Typeface applyStyles(
@Nullable Typeface typeface,
int style,
@@ -190,8 +219,9 @@
if (fontFamilyName == null) {
return typefaceStyle.apply(typeface == null ? Typeface.DEFAULT : typeface);
} else {
+ String FontFamilyRealName = FontFamilyMappingWithWeight(fontFamilyName, weight);
return ReactFontManager.getInstance()
- .getTypeface(fontFamilyName, typefaceStyle, assetManager);
+ .getTypeface(FontFamilyRealName, typefaceStyle, assetManager);
}
}
}
I've tried to compile then run it, and the result quite expected except the fontWeight 700, 800, 900 seems not affected
Current Result with <Text/> Component :
Current Result with <TextInput/> Component :
You can over ride everything. Even private apis. You can check my project sourcecode to understand what i mean
Just define new class that inherits from that java api
My project has many examples of this
Private api needs to be reimplemented in child class.. but few lines of code
@cortinico Im not a java expert but this doesnt feel right com/facebook/react/views/text/ReactTypefaceUtils.java:
The RN upgrade has made the android version ugly
Im not a java expert but this doesnt feel right
com/facebook/react/views/text/ReactTypefaceUtils.java:
Can you clarify why it doens't feel right @krisidmisso
@cortinico
- "bold" doesnt always have a 700 weight. There are fonts that dont have all these values, instead I think it should be something between 400 and the max font weight the font supports. So statically typing all the cases wont always work. Also, isnt there a way to handle string to integer conversion?
- shouldt there be any
"bold"case inparseFontStyle?
Again, I dont understand java but this issue is boring and it challenges us in every project. I have bookmarked this solution https://stackoverflow.com/questions/38815234/how-to-add-fonts-for-different-font-weights-for-react-native-android-project but I dont think this should be the best way to achieve font styles
I dont remember having this issue with old RN versions
I dont remember having this issue with old RN versions
- Are you able to bisect in which version of RN this got introduced?
- Also can we please create a repro with this template: https://github.com/react-native-community/reproducer-react-native
Hello Everyone! I'm running into the same problem and trying to wrap my head around the issue.
A couple of things don't add up for me.
Font weight on Android for custom fonts only applies regular weight for 100 - 600 and bold for 700 - 900. For default font family however it works fine for all the ranges.
If it's Android's limitation and the only way to make it work is to make an XML font definition as described in this comment: https://github.com/facebook/react-native/issues/42116#issuecomment-1876854067 then does it mean the Android system font has separate fonts defined for Thin, ExtraLight, Light, Regular, Medium, SemiBold, Bold ,ExtraBold and Black?
In that case it doesn't make sense to me because I couldn't find the place where RN converts 100- 900 values to Android font names but default RN text still works.
Please let me know if I'm missing something and how I can help 🙏
I have a similar issue on RN 0.76 but I'm not sure if it's directly related? https://github.com/facebook/react-native/issues/47656
FTR, I made it work in android referencing below official example with custom font:
-
make custom xml to cover all fonts: https://github.com/facebook/react-native/blob/main/packages/rn-tester/android/app/src/main/res/font/rubik.xml
-
register in main application's onCreate: https://github.com/facebook/react-native/blob/main/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.kt#L121