Fonts don't load reliably with expo-fonts + @expo-google-fonts
Minimal reproducible example
https://github.com/nabn/expo-font-config-plugin-issue
Summary
Loading google fonts using expo-font config plugin + @expo-google-fonts doesn't seem to work.
Dynamic loading using useFonts intermittently works.
Steps to reproduce
The with-router-tailwind template is used here, but problem exists in the blank templte too.
- create repo:
bun create-expo-app -e with-router-tailwind - add dev client:
bunx expo install expo-dev-client - add font lib & a google font:
bunx expo install expo-font @expo-google-fonts/dm-serif-display - configure the config plugin
plugins: [
[
"expo-font",
{
"fonts": [
"node_modules/@expo-google-fonts/dm-serif-display/DMSerifDisplay_400Regular.ttf",
"node_modules/@expo-google-fonts/dm-serif-display/DMSerifDisplay_400Regular_Italic.ttf"
]
}
]
]
- use in app:
<Text
style={{
fontFamily: "DMSerifDisplay_400Regular",
fontSize: 30,
}}
>
DM Serif Display
</Text>
<Text
style={{
fontFamily: "DMSerifDisplay_400Regular_Italic",
fontSize: 30,
}}
>
DM Serif Display Italic
</Text>
- build and run:
bunx expo run:ios
Expected Fonts are applied to text Actual Fonts are not applied.
https://github.com/expo/expo/assets/1693287/9e25acb8-82b7-44c6-b5e0-bf7d04b8f4eb
Environment
expo-env-info 1.2.0 environment info:
System:
OS: macOS 14.2.1
Shell: 5.9 - /bin/zsh
Binaries:
Node: 18.19.0 - ~/.local/share/mise/installs/node/18/bin/node
Yarn: 1.22.21 - ~/.bun/bin/yarn
npm: 10.2.3 - ~/.local/share/mise/installs/node/18/bin/npm
Watchman: 2023.12.04.00 - /opt/homebrew/bin/watchman
Managers:
CocoaPods: 1.14.3 - /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms: DriverKit 23.2, iOS 17.2, macOS 14.2, tvOS 17.2, visionOS 1.0, watchOS 10.2
IDEs:
Android Studio: 2023.1 AI-231.9392.1.2311.11255304
Xcode: 15.2/15C500b - /usr/bin/xcodebuild
npmPackages:
expo: ^50.0.1 => 50.0.2
expo-router: ~3.4.1 => 3.4.3
react: 18.2.0 => 18.2.0
react-dom: 18.2.0 => 18.2.0
react-native: 0.73.2 => 0.73.2
react-native-web: ~0.19.6 => 0.19.10
Expo Workflow: managed
Currently, we are unable to make the new embedded font option (via the expo-font plugin) work at all. Following the instructions for using a font from @expo-google-fonts results in none of them being available within the app when using Expo Go. Errors like the following are thrown:
fontFamily "Montserrat_400Regular" is not a system font and has not been loaded through expo-font.
It works fine using the existing async loading via useFonts.
Thank you for filing this issue! This comment acknowledges we believe this may be a bug and there’s enough information to investigate it. However, we can’t promise any sort of timeline for resolution. We prioritize issues based on severity, breadth of impact, and alignment with our roadmap. If you’d like to help move it more quickly, you can continue to investigate it more deeply and/or you can open a pull request that fixes the cause.
@amandeepmittal - it looks like we might need to improve documentation on how to use the expo-font config plugin with google fonts.
I suspect what is happening in this case is that the font name is not actually the same name as the file. note this caveat:
Create a new native build, and you can now use the font in your project with the fontFamily style prop. On Android, the font family name will be the name of the font file without the extension. On iOS, the font family name will be read from the font file itself. We recommend naming the font file the same as the font family so the family name is consistent on both platforms. For example, if you have a font family named "Inter-Black" and name the file Inter-Black.otf, then the font family name will be Inter-Black on both Android and iOS.
(source)
Wouldn't the font not load at all if the name wasn't right? In the recording, dynamically loading the font is working.
I'm seeing the same issue on iOS, but on Android it does work.
In the local android folder (after removing and executing npm run android) I can see the ttf files in /app/src/main/assets/fonts, and when I run the app I see them rendered correctly.
In the local ios folder I cannot find the fonts, so they do not appear to have been copied to the native project. I also don't find any reference to them in the ios/Info.plist file (again I deleted the folder and ran npm run ios to rebuild the native app locally).
OK, I've got a step further ...
The example path in the docs is node_modules/@expo-google-fonts/inter/Inter_100Thin.ttf which works for the Android build but not for iOS.
I modified the path to be ./node_modules/@expo-google-fonts/inter/Inter_100Thin.ttf (note the "./" at the front!) and now I can see the fonts in the Resources in xcode and referenced in Info.plist. Unfortunately I still can't get the fonts to render 😅
OK, finally I have it working on both iOS and Android.
For me the keys to making it work were:
- Make sure the path starts with "./", for example "./node_modules/@expo-google-fonts/inter/Inter_400Regular.ttf"
- On Android, the font name is the same as the file name (ie., "Inter_400Regular")
- On iOS, the font name is name-style (ie., "Inter-Regular").
If you want to confirm what fonts are available in your build you can add the following objectiveC code to your AppDelegate.mm file before the return statement in didFinishLaunchingWithOptions:
// Get the sorted array of font family names
NSArray *familyNames = [[UIFont familyNames] sortedArrayUsingSelector:@selector(compare:)];
// Iterate over each family name
for (NSString *family in familyNames) {
// Get font names for the current family
NSArray *fontNames = [UIFont fontNamesForFamilyName:family];
// Print out the family and font names
NSLog(@"Family: %@ Font names: %@", family, fontNames);
}
... which prints e.g.:
Family: Inter Font names: (
"Inter-Regular",
"Inter-SemiBold"
)
Now I just need to make it work on web and I'll be golden 😄
Final note, I think:
On web I've gone back to the "dynamic" loading approach, since there's no native app to embed the font in anyways. There the font name is the same as Android, so I'm just switching on the platform at the point where I set up my theme:
fonts: {
body: Platform.OS === "ios" ? "Inter-Regular" : "Inter_400Regular",
heading: Platform.OS === "ios" ? "Syne-Regular" : "Syne_400Regular"
}
We figured that the font on iOS won't work the same way as on Android (by calling the font file name) if the font has multiple weights. In that case, we suggest using Platform such as:
<Text
style={{
fontFamily: Platform.select({
android: 'Inter_100Thin',
ios: 'Inter-Thin',
})
}}>
Inter Bold
</Text>
Similar to what @steveliles suggested.
Also, updating our documentation for now until we improve the way of handling fonts on iOS: https://github.com/expo/expo/pull/27023/files
This still seems to be a problem, I can't use a font in the project via app.json following @steveliles' steps. The problem happens with fonts downloaded in the assets folder or with expo-google-fonts. I'm using Expo Go on an Android and I get the error reported by @carbonatedcoder
I cleared the Expo Go cache and it still doesn't work
@Amystherdam, using the config plugin method using app config file doesn't work with Expo Go. You'll have to create a development build. We're in the process of updating the Fonts guide in the documentation to add more clarification about it. For a preview of the updated docs, see this: http://docs.expo.dev-pr-29903.s3-website-us-east-1.amazonaws.com/develop/user-interface/fonts/#with-expo-font-config-plugin
@Amystherdam, using the config plugin method using app config file doesn't work with Expo Go. You'll have to create a development build. We're in the process of updating the Fonts guide in the documentation to add more clarification about it. For a preview of the updated docs, see this: http://docs.expo.dev-pr-29903.s3-website-us-east-1.amazonaws.com/develop/user-interface/fonts/#with-expo-font-config-plugin
Link is broken
@jeremykanso, we published it a few days back: https://docs.expo.dev/develop/user-interface/fonts/#with-expo-font-config-plugin