Ospfolio

Two-way to change default font family in React Native

August 20, 2019 • ☕☕ 8 min read

In the time of writing this article, I am using React Native v0.60.4.

When you develop the app, sometimes we need to set a specific font to make its look consistency in both the iOS and Android platform. Today I’m going to show you how to use custom fonts and set as default one in React Native. You may find yourself asking questions like:

When I just started working on React Native for a few projects. I was confused by all of those questions too. I don’t have a firm grasp on some of the subtleties. I’ve since had a few “aha” moments that I want to share with you. This deep dive will make the answers to these questions look obvious to you.

TLDR;

The goal of this article isn’t to give you a list of bullet point recipes. It’s to help you truly get started. There won’t be much to learn. We’ll spend most of our time unlearning.

Why do MyApp sometimes get texts cut-off on some Android phone?

I have faced similar issues in OnePlus 5 or Xiaomi device. These issues only happen when you have chosen “OnePlus Slate” font in Settings. If you change the font to Roboto, the issues don’t occur.

Why do I need to set default font in my project?

Let’s ask ourselves a simple question “What’s the purpose of our app?“. If you can’t find one, you may see the question above that can be one reason. The other reasons are depending on your project case. Some clients provided a very clear UI guideline for their brand identity which making both platforms to look more consistency.

Why do I sometime get incorrect font name between iOS and Android?

Normally, Font is correctly named. But in some cases, you need to rename them. You need to use the PostScript name. If not, you may end up something like this.

Platform.select({
  ios: 'HelloWorld',
  android: 'HelloWorld-Regular'
})

To check PostScript name, you may open Font Book app on Mac and Press Cmd + i on that font

font book app

Before we link fonts to React Native project, we need to have font first. I will be using this Google Nunito Sans font. You can choose any fonts you like to, but font matters.

font matters

android/
ios/
src/
├── assets
│   ├── fonts/
│   │   ├── NunitoSans/
│   │   │   ├── NunitoSans-Regular.ttf
│   │   │   ├── NunitoSans-Bold.ttf
├── App.js

This is my folder structure of where font file located. As of React Native v0.60x or higher. You need to have react-native.config.js file due to rnpm inside package.json is deprecated.

Here is the sample of rnpm link to your font in your project’s package.json for React Native below v0.60x.

// package.json

"rnpm": {
 "assets": ["./src/assets/fonts/NunitoSans"]
}

In case, if you haven’t created it yet. you can simply run this command below from the root of the project.

// terminal

touch react-native.config.js

After you created please modify react-native.config.js file to code below and make sure your path is correct.

// react-native.config.js

module.exports = {
  assets: ['./src/assets/fonts/NunitoSans'],
}

When you finish the step above, we can start linking our fonts now. Please simply run this command below:

// terminal

react-native link
  • iOS

Next step, we need to open the project in Xcode. You can simply run this command below:

// terminal

xed -b ios

Next, navigate to Info tab and make sure it has Fonts provided by application with its values.

Info

Next, navigate to Build Phases tab and make sure our font was added into Copy Bundle Resources

Build Phases

  • Android

Next step, we need to see our fonts were linked inside our Android folder.

Font linked in Android

Okay, look like everything was good to go. Let’s test it out by modifying our App.js to code sample below:

// App.js

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

export const App = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>Ospfolio Default Font</Text>
      <Text style={styles.customText}>Ospfolio Custom Font</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#070825',
  },
  text: {
    color: '#ffc100',
    fontSize: 24,
  },
  customText: {
    color: '#ffc100',
    fontSize: 24,
    fontFamily: 'NunitoSans-Regular',
  },
});

Success Linked

How do I set default font family as global in React Native Project?

Now you know how to link fonts and use it to React Native project. Next, we went deep dive to see how can we handle this by reducing more code.

If you look closely in the above solution, every time we need that font, we have to set fontFamily style to every component that uses it. It works believe me, but don’t you feel it will duplicate your work when you want to change to the new font? So how can we handle this to avoid DRY principle (Don’t Repeat Yourself)? Well, I will show you how to handle this in two-way.

“Unlearn what you have learned.” — Yoda

Yoda sniffing the air. Caption: “I smell bacon.”

Option 1: Using Custom Component

First, we will create a new file and named it as CustomText.js.

android/
ios/
src/
├── assets
│   ├── fonts/
│   │   ├── NunitoSans/
│   │   │   ├── NunitoSans-Regular.ttf
│   │   │   ├── NunitoSans-Bold.ttf
├── modules
│   ├── common/
│   │   ├── CustomText.js
├── App.js

Next, we will modify our CustomText.js to code sample below

// CustomText.js

import React from 'react';
import { StyleSheet, Text  } from 'react-native';

export const CustomText = props => <Text style={styles.text}>{props.children}</Text>

const styles = StyleSheet.create({
  text: {
    fontFamily: 'NunitoSans-Regular',
  }
});

Next, we will modify our App.js to use that CustomText component.

// App.js

import React from 'react';
import { StyleSheet, View } from 'react-native';
import { CustomText } from './modules/common/CustomText';

const App = () => {
  return (
    <View style={styles.container}>
      <CustomText>Ospfolio Custom Font 101</CustomText>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#070825'
  },
});

As you can see, we just import our CustomText.js to every component that uses it. And if we want to change the font or add any custom styles, we head to CustomText.js to change it and it will apply to all components that using CustomText.js. Aha! Cool right?

Option 2: Using Text component from react-native

Our first solution work as expected. Now we will go deeper to see what’s we can reduce more boilerplate code. Keep in mind that this solution is kind of hacky. First, we will create a new file and named it as typography.js.

index.js
android/
ios/
src/
├── assets
│   ├── fonts/
│   │   ├── NunitoSans/
│   │   │   ├── NunitoSans-Regular.ttf
│   │   │   ├── NunitoSans-Bold.ttf
├── modules
│   ├── common/
│   │   ├── CustomText.js
├── utils
│   ├── typography.js
├── App.js

Next, we will modify our typography.js to the sample code below:

// typography.js

import React from 'react'
import { Text, Platform, StyleSheet } from 'react-native'

export const typography = () => {
  const oldTextRender = Text.render
  Text.render = function(...args) {
    const origin = oldTextRender.call(this, ...args)
    return React.cloneElement(origin, {
      style: [styles.defaultText, origin.props.style],
    })
  }
}

const styles = StyleSheet.create({
  defaultText: {
    fontFamily: 'NunitoSans-Regular',
  }
});

Next, we will modify our index.js to use typography.

// index.js

import { AppRegistry } from 'react-native'
import { App } from './src/App'
import { name as appName } from './app.json'
import { typography } from './src/utils/typography'

typography()

AppRegistry.registerComponent(appName, () => App)

Success Linked

Ahaa! Just one call and it is applied to all as we did in our first solution. But for this, we don’t need to import CustomText.js to every component anymore. It’s really really helpful and reduces more code. This solution also works with React Native < v60.x In React Native docs, they would recommend to the first solution. Check RN Docs here

In Closing

Now that you know pretty much everything about link custom font and make it default in RN project. Does it make sense? Did I miss something? (I haven’t run out of paper yet!)

Thanks for reading.