---
title: Fonts
description: Learn how to integrate custom fonts in your app using local files or Google Font packages
---
Android and iOS come with their own set of platform fonts. To provide a consistent user experience and enhance your app's branding, you can use custom fonts.
This guide covers different ways you can add and load a custom font into your project and also provides additional information related to fonts.
## Add a custom font
There are two ways you can add a custom font into your project:
- Add a font file into your local assets. For example, a font file in the **assets/fonts** directory.
- Install a Google Font package. For example, installing [`@expo-google-fonts/inter`](https://www.npmjs.com/package/@expo-google-fonts/inter) package.
### Supported font formats
Expo SDK officially supports OTF and TTF font formats across Android, iOS and web platforms. If your font is in another font format, you have to set up advanced configuration to support that format in your project.
### Variable fonts
Variable fonts, including variable font implementations in OTF and TTF, do not have support across all platforms. For full platform support, use static fonts. Alternatively, use a utility such as [fontTools](https://fonttools.readthedocs.io/en/latest/varLib/mutator.html) to extract the specific axis configuration you want to use from the variable font and save it as a separate font file.
### How to choose between OTF and TTF
If the font you're using has both OTF and TTF versions, prefer OTF. The **.otf** files are smaller than **.ttf** files. Sometimes, OTF also renders slightly better in certain contexts.
## Use a local font file
Copy the file into your project's **assets/fonts** directory.
> **info** **assets/fonts** directory path is a common convention in React Native apps to put font files. You can place these files elsewhere if you follow a custom convention.
Two ways to use the local font file in your project:
- Embed the font file with [`expo-font` config plugin](/versions/latest/sdk/font/#configuration-in-app-config).
- Loading the font file with [`useFonts`](/versions/latest/sdk/font/#usefontsmap) hook at runtime asynchronously.
### With `expo-font` config plugin
The `expo-font` config plugin allows embedding one or more font files in your project's native code. It supports `ttf` and `otf` for both Android and iOS, and `woff` and `woff2` are supported on iOS only. This is the recommended method for adding fonts to your app due to its benefits:
- Fonts are available immediately when the app starts on a device.
- No additional code required to load fonts in a project asynchronously when the app starts.
- Fonts are consistently available across all devices where the app is installed because they're bundled within the app.
However, this method also has some limitations:
- Doesn't work with Expo Go since this method requires [creating a development build](/develop/development-builds/create-a-build/).
To embed a font in a project, follow the steps below:
After adding a custom font file in your project, install the `expo-font` library.
Add the config plugin to your [app config](/versions/latest/config/app/#plugins) file. The configuration must contain the path to the font file using [`fonts`, `android` or `ios`](/versions/latest/sdk/font/#configurable-properties) properties which take an array of one or more font definitions. The path to each font file is relative to the project's root.
The example below showcases all valid ways a font can be specified: as an array of objects that specify `fontFamily` and other properties, or an array of paths to font files.
For Android, you can specify the `fontFamily`, `weight`, and optionally `style` (defaults to `"normal"`), which will embed the fonts as native [XML resources](https://developer.android.com/develop/ui/views/text-and-emoji/fonts-in-xml). If you provide only the font file paths in an array, the file name becomes the font family name on Android. iOS always extracts the font family name from the font file itself.
If you plan to refer to fonts using just the `fontFamily`, provide an array of font paths (see `FiraSans-MediumItalic.ttf` below) and follow our [recommendation for file naming](#how-to-determine-which-font-family-name-to-use).
If you want to refer to fonts using a combination of `fontFamily`, `weight`, and `style`, provide an array of objects (see `Inter` below).
```json app.json
{
"expo": {
"plugins": [
[
"expo-font",
{
"fonts": [
/* @info Refer to this font using fontFamily: 'FiraSans-MediumItalic' */
"./assets/fonts/FiraSans-MediumItalic.ttf"
/* @end */
],
"android": {
"fonts": [
{
"fontFamily": "Inter",
"fontDefinitions": [
{
/* @info Refer to this font using fontFamily: 'Inter', fontWeight: '700', fontStyle: 'italic' */
"path": "./assets/fonts/Inter-BoldItalic.ttf",
/* @end */
"weight": 700,
"style": "italic"
},
{
"path": "./assets/fonts/Inter-Bold.ttf",
"weight": 700
}
]
}
]
},
"ios": {
"fonts": ["./assets/fonts/Inter-Bold.ttf", "./assets/fonts/Inter-BoldItalic.ttf"]
}
}
]
]
}
}
```
After embedding the font with the config plugin, create a [new development build](/develop/development-builds/create-a-build/) and install it on your device or Android Emulator or iOS Simulator.
You can use the font with `<Text>` by specifying the `fontFamily` style prop. The examples below correspond to the fonts defined in the configuration above.
```tsx
<Text style={{ fontFamily: 'Inter', fontWeight: '700' }}>Inter Bold</Text>
<Text style={{ fontFamily: 'Inter', fontWeight: '700', fontStyle: 'italic' }}>Inter Bold Italic</Text>
<Text style={{ fontFamily: 'FiraSans-MediumItalic' }}>Fira Sans Medium Italic</Text>
```
- **Android:** Copy font files to **android/app/src/main/assets/fonts**.
- **iOS:** See [Adding a Custom Font to Your App](https://developer.apple.com/documentation/uikit/text_display_and_fonts/adding_a_custom_font_to_your_app) in the Apple Developer documentation.
#### How to determine which font family name to use
- If you provide fonts as an array of file paths (as described above), on Android, the file name (without the extension) becomes the font family name. On iOS, the font family name is read from the font file itself. We recommend naming the font file same as its [PostScript name](#what-is-postscript-name-of-a-font) so the font family name is consistent on both platforms.
- If you use the object syntax, provide the "Family Name". This can be found in the Font Book app on macOS, [fontdrop.info](https://fontdrop.info/) or other programs.
The **PostScript name** of a font file is a unique identifier assigned to the font that follows Adobe's PostScript standard. It is used by operating systems and apps to refer to the font. It is not a font's **display name**.
For example, Inter Black font file's PostScript name is `Inter-Black`.
_Screenshot from Font Book app on macOS._
### With `useFonts` hook
The `useFonts` hook from `expo-font` library allows loading the font file asynchronously. This hook keeps track of the loading state and loads the font when an app is initialized.
It works with all Expo SDK versions and with Expo Go. To load a font in a project using `useFonts` hook, follow the steps below:
After adding a custom font file in your project, install the `expo-font` and `expo-splash-screen` libraries.
The [`expo-splash-screen`](/versions/latest/sdk/splash-screen/) library provides `SplashScreen` component that you can use to prevent rendering the app until the font is loaded and ready.
Map the font file using the `useFonts` hook in a top level component such as the root layout (**app/layout.tsx**) file in your project:
```tsx app/_layout.tsx
/* @info Import <CODE>useFonts</CODE> hook from <CODE>expo-font</CODE>. */ import { useFonts } from 'expo-font'; /* @end */
/* @info Import <CODE>SplashScreen</CODE> so that when the fonts are not loaded, we can continue to show <CODE>SplashScreen</CODE>. */ import * as SplashScreen from 'expo-splash-screen'; /* @end */
/* @info This prevents <CODE>SplashScreen</CODE> from auto hiding while the fonts are in loading state. */
SplashScreen.preventAutoHideAsync();
/* @end */
/* @info Map the font file using <CODE>useFonts</CODE> hook. */
const [loaded, error] = useFonts({
'Inter-Black': require('./assets/fonts/Inter-Black.otf'),
});
/* @end */
useEffect(() => {
if (loaded || error) {
/* @info After the custom fonts have loaded, we can hide the splash screen and display the app screen. */
SplashScreen.hideAsync();
/* @end */
}
}, [loaded, error]);
if (!loaded && !error) {
return null;
}
return (
/* @hide ... */ /* @end */
)
}
```
Use the font on the `<Text>` by using `fontFamily` style prop in a React component:
```tsx
<Text style={{ fontFamily: 'Inter-Black' }}>Inter Black</Text>
```
## Use Google Fonts
Expo has first-class support for all fonts listed in [Google Fonts](https://fonts.google.com/). They are available using [`@expo-google-fonts`](https://github.com/expo/google-fonts) library. With any of the font package from this library, you can quickly integrate that font and its variants.
Two ways to use a Google Font in your project:
- Embed the installed font with [`expo-font` config plugin](/versions/latest/sdk/font/#configuration-in-appjsonappconfigjs).
- Load the installed font with [`useFonts`](/versions/latest/sdk/font/#usefontsmap) hook at runtime asynchronously.
### With `expo-font` config plugin
> **Note:** Embedding a Google Font using `expo-font` config plugin has same benefits and limitations as embedding a custom font on your own. See [using a local font file with `expo-font` config plugin](#with-expo-font-config-plugin) for more information.
Install the font package. For example, to use Inter Black font, install the [`@expo-google-fonts/inter`](https://www.npmjs.com/package/@expo-google-fonts/inter) package with the command below.
Add the config plugin to your [app config](/versions/latest/config/app/#plugins) file. The configuration must contain the path to the font file using [`fonts`](/versions/latest/sdk/font/#configurable-properties) property which takes an array of one or more font files. The path to the font file is defined from the font package inside the `node_modules` directory. For example, if you have a font package named `@expo-google-fonts/inter`, then the name of the file is **Inter_900Black.ttf**.
```json app.json
{
"plugins": [
[
"expo-font",
{
/* @info The path to the font file is defined from the font package inside the node_modules directory. */
"fonts": ["node_modules/@expo-google-fonts/inter/900Black/Inter_900Black.ttf"]
/* @end */
}
]
]
}
```
After embedding the font with the config plugin, create a [new development build](/develop/development-builds/create-a-build/) and install it on your device or Android Emulator or iOS Simulator.
On Android, you can use the font file name. For example, `Inter_900Black`. On iOS, use the font and its weight name ([PostScript name](#what-is-postscript-name-of-a-font)). The example below demonstrates how to use [`Platform`](https://reactnative.dev/docs/platform-specific-code#platform-module) to select the correct font family name for each platform:
{/* prettier-ignore */}
```tsx
// Inside a React component:
<Text
style={{
/* @info */
fontFamily: Platform.select({
android: 'Inter_900Black',
ios: 'Inter-Black',
}),
/* @end */
}}>
Inter Black
</Text>
```
### With `useFonts` hook
> **Note:** Loading a Google Font using `useFonts` hook has same benefits and limitations as embedding a custom font on your own. See [using a local font file with `useFonts` hook](#with-usefonts-hook) for more information.
Each google Fonts package provides the `useFonts` hook to load the fonts asynchronously. This hook keeps track of the loading state and loads the font when an app is initialized. The font package also imports the font file so you don't have to explicitly import it.
Install the Google Fonts package, `expo-font` and `expo-splash-screen` libraries.
The [`expo-splash-screen`](/versions/latest/sdk/splash-screen/) library provides `SplashScreen` component that you can use to prevent rendering the app until the font is loaded and ready.
After installing the font package, map the font using the `useFonts` hook in a top level component such as the root layout (**app/layout.tsx**) file in your project:
```tsx app/_layout.tsx
// Rest of the import statements
/* @info Import <CODE>Inter_900Black</CODE> and <CODE>useFonts</CODE> hook from <CODE>@expo-google-fonts/inter</CODE>*/
/* @end */
/* @info Import <CODE>SplashScreen</CODE> so that when the fonts are not loaded, we can continue to show <CODE>SplashScreen</CODE>. */
/* @end */
/* @info This prevents <CODE>SplashScreen</CODE> from auto hiding while the fonts are in loading state. */
SplashScreen.preventAutoHideAsync();
/* @end */
/* @info Map the font file using <CODE>useFonts</CODE> hook. */
const [loaded, error] = useFonts({
Inter_900Black,
});
/* @end */
useEffect(() => {
if (loaded || error) {
/* @info After the custom fonts have loaded, we can hide the splash screen and display the app screen. */
SplashScreen.hideAsync();
/* @end */
}
}, [loaded, error]);
if (!loaded && !error) {
return null;
}
return (
/* @hide ... */ /* @end */
)
}
```
Use the font on the `<Text>` by using `fontFamily` style prop in a React component:
```tsx
<Text style={{ fontFamily: 'Inter_900Black' }}>Inter Black</Text>
```
## Additional information
### Minimal example
<BoxLink
title={
<>
expo-font usage
</>
}
description="See usage section in Expo Fonts API reference for a minimal example of using a custom font."
href="/versions/latest/sdk/font/#usage"
Icon={BookOpen02Icon}
/>
### Beyond OTF and TTF
If your font is in format other than OTF or TTF, you have to [customize the Metro bundler configuration to include it as an extra asset](/guides/customizing-metro#adding-more-file-extensions-to-assetexts) for it to work. In some cases, rendering a font format that a platform doesn't support may cause your app to crash.
For reference, the following table provides the list formats that work on each native platform:
| Format | Android | iOS | Web |
| ------ | ----------- | ----------- | ----------- |
| bdf | | | |
| dfont | | | |
| eot | | | |
| fon | | | |
| otf | | | |
| ps | | | |
| svg | | | |
| ttc | | | |
| ttf | | | |
| woff | | | |
| woff2 | | | |
### Platform built-in fonts
If you don't want to use a custom font by specifying a `fontFamily`, platform's default font will be used. Each platform has a set of built in fonts. On Android, the default font is Roboto. On iOS, it's SF Pro.
A platform's default font is usually easy-to-read. However, don't be surprised when the system default font is changed to use another font that is not easy to read. In this case, use your custom font so you have precise control over what the user will see.
### Handle `@expo/vector-icons` initial load
When the icons from `@expo/vector-icons` library load for the first time, they appear as invisible icons in your app. Once they load, they're cached for all the app's subsequent usage. To avoid showing invisible icons on your app's first load, preload during the initial loading screen with [`useFonts`](/versions/latest/sdk/font/#usefontsmap). For example:
```tsx app/_layout.tsx
useFonts([require('./assets/fonts/Inter-Black.otf', Ionicons.font)]);
return (
/* @hide ... */ /* @end */
)
}
```
Now, you can use any icon from the `Ionicons` library in a React component:
```tsx
```
### Loading a remote font directly from the web
> **warning** **If you're loading remote fonts, make sure they are being served from an origin with CORS properly configured**. If you don't do this, your remote font might not load properly on the web platform.
Loading fonts from a local asset is the safest way to load a font in your app. When including fonts as local assets, after you submit your app to the app stores, these fonts are bundled with the app download and will be available immediately. You don't have to worry about CORS or other potential issues.
However, loading a font file directly from web is done by replacing the `require('./assets/fonts/FontName.otf')` with the URL of your font as shown in the example below.
```tsx
const [loaded, error] = useFonts({
'Inter-SemiBoldItalic': 'https://rsms.me/inter/font-files/Inter-SemiBoldItalic.otf?v=3.12',
});
if (!loaded || !error) {
return null;
}
return (
<View style={styles.container}>
<Text style={{ fontFamily: 'Inter-SemiBoldItalic', fontSize: 30 }}>Inter SemiBoldItalic</Text>
<Text style={{ fontSize: 30 }}>Platform Default</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
```