(React Native) Create a Custom Text Component with Custom font-family

Kenta Kodashima
Nerd For Tech
Published in
6 min readDec 31, 2019

Today, I am going to share my knowledge to create a handy reusable custom text component in React Native. The final source code is available on my Github.

Prerequisites

  • I will be using Typescript in this article
  • The project is generated using pure React Native
  • Basic knowledge of pure React Native development

My Environment

  • React Native: 0.61.5
  • macOS Catalina: Version 10.15.2 (19C57)
  • Typescript: 3.7.4

1. Generate and setup a React Native project

First, generate a new React Native project with the following code.

react-native init CustomTextExample

Next, add the necessary dependencies.

// Add typescript
npm i -D typescript react-native-typescript-transformer
// Add eslint with typescript plugin
npm i -D eslint
@typescript-eslint/parser @typescript-eslint/eslint-plugin
// Add types
npm i -D @types/react @types/react-native
// Optionally, you can add prettier
npm i -D prettier eslint-config-prettier eslint-plugin-prettier

Then, modify the .eslinttrc.js file something like below to configure Typescript stuff.

// .eslinttrc.jsmodule.exports = {
root: true,
parser: '
@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2018, // Allow to parse modern ECMAScript features
sourceType: 'module', // Allow to use imports
ecmaFeatures: {
jsx: true,
},
},
plugins: ['
@typescript-eslint'],
extends: [
'eslint:recommended',
'plugin:
@typescript-eslint/recommended',
'plugin:react/recommended',
'prettier',
'prettier/@typescript-eslint',
],
rules: {
semi: 0,
'ordered-imports': 0,
'object-literal-sort-keys': 0,
'member-ordering': 0,
'jsx-no-lambda': 0,
'jsx-boolean-value': 0,
'no-console': 0,
'no-empty-interface': 0,
'interface-name': [0, 'always-prefix'],
'
@typescript-eslint/no-unused-vars': 0,
'
@typescript-eslint/camelcase': 0,
'
@typescript-eslint/no-explicit-any': 0,
'
@typescript-eslint/explicit-function-return-type': [
'warn',
{
'allowExpressions': 1,
'allowTypedFunctionExpressions': 1
}
]
},
env: {
es6: true,
node: true,
}
}

Finally, rename the App.js and index.js files to App.tsx and index.ts. Also, create the src folder at the root directory and move the App.tsx file in the src directory. After moving the App.tsx file, don’t forget to also modify the directory in the index.ts file.

At this point, you might have some typing errors. We will fix those errors later when we create the CustomText component, so just ignore those errors for now.

That’s everything for the setup.

2. Download Google Fonts

Next, we need the font to use it in the app. Go to the Google Fonts website and download any font that you want to use. All you need to do here is to search for a font and click on the download icon at the top-right of the modal. I use ‘Lato’ for this tutorial.

Download the font files

After downloading the font, we need to configure the font to use it in the app. Under the root directory of the app, create the /src/assets/fonts/ directory and put your font files there.

Put the font files

Then, at the root directory of the app, create the file named react-native.config.js and paste the code below.

// react-native.config.jsmodule.exports = {
assets: ['./src/assets/fonts'],
}

Finally, run the following code on your terminal.

react-native link

Now, our app should recognize the downloaded font.

3. Create the CustomText component

Now, it’s time to create the CustomText component. Under the src directory, create the components folder. Inside the components folder, create the file and name it CustomText.tsx . Then, add the boilerplate below.

// CustomText.tsximport React, { FunctionComponent } from 'react'
import {
Text,
StyleSheet
} from 'react-native'
type CustomTextProps = {}const CustomText: FunctionComponent<CustomTextProps> = ({ children }) => {
return (
<Text>
{children}
</Text>
)
}
const styles = StyleSheet.create({})export default CustomText

4. Make the font family configurable

To make the font family configurable via props, make the following changes to the component.

// CustomText.tsx...type CustomTextProps = {
textType?: 'regular' | 'bold' | 'light'
}
const CustomText: FunctionComponent<CustomTextProps> = ({ children, textStyle }) => {
let textStyle: {}
switch (textType) {
case 'regular':
textStyle = styles.regular
break
case 'bold':
textStyle = styles.bold
break
case 'light':
textStyle = styles.light
break
default:
textStyle = styles.regular
break
}
return (
<Text style={textStyle}>
{children}
</Text>
)
}
const styles = StyleSheet.create({
regular: {
fontFamily: 'Lato-Regular'
},
bold: {
fontFamily: 'Lato-Bold'
},
light: {
fontFamily: 'Lato-Light'
}

})
export default CustomText

In the code above, the following changes were made.

  1. Styles in StyleSheet.create()
    Define the font families that you want to have here.
  2. textType prop type
    Add textType prop type in CustomTextProps type to receive the prop to configure which font family to use. In this case, I can just pass ‘regular’, ‘bold’ or ‘light’ as the value. Don’t forget to add textType to destructured props also.
  3. The switch statement
    The switch statement is used to assign a font family from the styles constant depending on the textType prop. I store it into the variable called textStyle and assign it as the style for the Text component inside the return statement.

5. Make the component be able to receive custom styles

To pass custom styles from the parent component, we need a little bit more work. Add the following changes below.

// CustomText.tsximport React, { FunctionComponent } from 'react'
import {
StyleSheet,
Text,
TextStyle
} from 'react-native'
type CustomTextProps = {
style?: TextStyle | TextStyle[]
textType?: 'regular' | 'bold' | 'light'
}
const CustomText: FunctionComponent<CustomTextProps> = ({ children, textStyle, style }) => {
let textStyle: {}
switch (textType) {
...
}
const passedStyles = Array.isArray(style) ? Object.assign({}, ...style) : stylereturn (
<Text style={[textStyle, { ...passedStyles } ]}>
{children}
</Text>
)
}
const styles = StyleSheet.create({
...
})
export default CustomText

In the code above, the following changes were made.

  1. style prop type
    Import the TextStyle type from react-native and add style? prop type in CustomTextProps type. Adding ? at the end makes it an optional prop. The type will be either of TextStyle or TextStyle[] . This is because the components in React usually take an object of styles or an array of style objects.
  2. The passedStyles constant
    If the style prop is passed an array of style objects, we cannot assign the values directly. Object.assign({}, …style) will spread the values of the passed array and assign it to the empty object. Using the ternary operator, an array is spread into an object if the type of the style prop is an array before it gets stored into the passedStyles constant.
  3. Pass both of textStyle and passedStyles
    Finally, pass passedStyles as one of the style prop values.

6. Modify the App.tsx to display CustomText

Finally, modify the App.tsx file to display our CustomText.

import React, { Component } from 'react'
import {
StyleSheet,
SafeAreaView,
View
} from 'react-native'
import CustomText from './components/CustomText'
class App extends Component {
render() {
const { container, customTextStyle } = styles

return (
<SafeAreaView style={container}>
<View>
<CustomText textType='light' style={[customTextStyle, { color: 'blue' }]}>Light</CustomText>
<CustomText textType='regular' style={[customTextStyle, { color: 'red' }]}>Regular</CustomText>
<CustomText textType='bold' style={[customTextStyle, { color: 'green' }]}>Bold</CustomText>
</View>
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
customTextStyle: {
fontSize: 16,
marginBottom: 8
}
})
export default App

If you run the app, you can see that the font families and each text styles are applied properly as the screenshot below.

CustomText with custom fonts and styles

That’s everything for this article.

Resources:

--

--

Kenta Kodashima
Nerd For Tech

I'm a Software Engineer based in Vancouver. Personal Interests: Books, Philosophy, Piano, Movies, Music, Studio Ghibli.