Editor’s note: This article was updated on 3 May 2022 to reflect the most recent information regarding react-native-vector-icons, including a quick fix for an auto-linking error that sometimes occurs in iOS.
When it comes to UI/UX, fonts and icons matter. Icons serve as a visual aid for users to navigate your app, and your choice of font (and font color) sets the tone for your app or brand.
Let’s be real: you’d be unlikely to purchase life insurance from a company that uses a cartoonish font such as Alloy Ink or Vegan Style in its contracts. And I couldn’t imagine an app without any icons. Seriously, if you know of one in the App Store, drop me a comment with a link — I’m curious!
In this React Native tutorial, we’ll show you how to:
- Set up a bare-bones React Native project with TypeScript
- Configure
react-native-vector-icons
and link custom fonts with zero native code - Build components to consume our font family and icons
The full source code associated with this demo is available on GitHub.
Jump ahead:
- Creating a React Native project
- Linking and unlinking with React Native Asset
- Creating a text component in React Native
- React Native Vector Icons
Creating a React Native project
To initialize a React Native project, paste the following into your terminal:
npx react-native init yourAppNameHere --template react-native-template-typescript && cd yourAppNameHere
This will create a new React Native project with a TypeScript template. Navigate to the project folder.
The next step is to build our app for each OS. First, iOS:
yarn run ios
Now, for Android:
yarn run android
Linking and unlinking with React Native Asset
As software developers, anything that improves our workflow is a welcome change. React Native Asset makes linking and unlinking more straightforward than using react-native link
.
First, install react-native-asset
globally:
yarn global add react-native-asset
In your project folder, create a new folder called assets
, then create another folder inside it called fonts
. Or you can use the terminal:
mkdir -p assets/fonts
Head over to Google Fonts to download a font family. For this example, we’re going with Nunito, but feel free to diverge with a font of your choice.
Once you’ve downloaded the file, unzip it and add your chosen font weights to the fonts folder:
Now, create a new file in your project folder called react-native.config.js
:
touch react-native.config.js
Then, add the following:
module.exports = { assets: ['./assets/fonts'], };
Finally, use React Native Asset to link the font files. Type the following in your terminal:
react-native-asset
If you need to remove and unlink a font, simply delete it from the fonts
folder, then run react-native-asset
again. Simple as that.
Creating a text component in React Native
Let’s create a custom text component to consume our new fonts. Create a folder called components
with a file inside called Text.tsx
, then add the following code:
import React from 'react'; import { Text as ReactText, StyleSheet, StyleProp, TextStyle, } from 'react-native'; type TextProps = { children: React.ReactNode; style?: StyleProp<TextStyle>; }; export const Text = ({style, children}: TextProps) => { return <ReactText style={[styles.font, style]}>{children}</ReactText>; }; const styles = StyleSheet.create({ font: { fontFamily: 'Nunito-Regular', }, });
The above code creates a Text
component with a font-family
of Nunito
and a regular font-weight
that we can use across our app. We get the children and style types (TextProps
) from React Native.
Now that we have our Text
component, let’s use it!
Replace your App.tsx
file with the following:
import React from 'react'; import {SafeAreaView, StyleSheet, StatusBar} from 'react-native'; import {Text} from './components/Text'; const App = () => { return ( <> <StatusBar barStyle="dark-content" /> <SafeAreaView style={styles.container}> <Text>This font-weight is 'regular' </Text> <Text style={styles.boldFont}>This font-weight is 'bold' </Text> </SafeAreaView> </> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, boldFont: { fontFamily: 'Nunito-Bold', }, }); export default App;
Notice that we have two different font-weight
s. Our Text
component on line 11 has a bold font-weight
. To achieve this, override the font-weight
settings with a bold font using StyleSheet.create
(line 23), then pass the value to the style prop in the Text
component.
React Native Vector Icons
With over 3,000 free icons and 15.7k GitHub stars, React Native Vector Icons is an excellent choice for all your icon needs. Many popular UI libraries, such as Magnus UI, React Native Paper, and React Native Elements, use React Native Vector Icons, so you’re in good company! And if you don’t find what you’re looking for, you can even make your own icons.
To use this package you need to install it. Head over to your terminal and type:
yarn add react-native-vector-icons && yarn add -D @types/react-native-vector-icons
Installing react-native-vector-icons for iOS
Install the React Native Vecor Icons library and dev dependency in iOS, like so:
cd ios && pod install && cd .. && yarn run ios
Next, navigate to your iOS folder, install your project’s CocoaPods
, then navigate back to your project folder.
Troubleshooting auto-linking or updating errors with iOS
If you happen to run into trouble with auto-linking or updating errors while installing React Native Vector Icons on iOS, here’s a neat little trick to fix the issue. Run:
yarn react-native link react-native-vector-icons && yarn react-native unlink react-native-vector-icons && yarn ios
Installing react-native-vector-icons for Android
Install the React Native Vecor Icons library and dev dependency on Android by opening android/app/build.gradle
(not android/build.gradle
) and adding this import statement:
import org.apache.tools.ant.taskdefs.condition.Os
Then, run the following command in the terminal:
yarn run android
Building an icon component in React Native
Now we’re going to build a reusable icon component.
In your components
folder, create a new file called Icon.tsx
:
cd components && touch Icon.tsx && cd ..
Then, add the following code:
import React from 'react'; import MIcon from 'react-native-vector-icons/MaterialCommunityIcons'; MIcon.loadFont(); type IconSizeProps = { iconSizes: keyof typeof IconSizes; }; export interface IconProps { size: IconSizeProps['iconSizes']; name: string; color: string; } export const IconSizes = { small: 13, medium: 18, large: 23, extraLarge: 27, }; export const MaterialIcon = ({size, name, color}: IconProps) => ( <MIcon name={name} size={IconSizes[size]} color={color} /> );
For each icon bundle you want to use, import and load it as we have in line 2 (import Material Community Icons bundle set) and line 4 (load the icon bundle).
Loading the icons this way eliminates the need to add any native code to use them.
We can export the components with three props that allow us to control the color, size, and type of icon:
size
is predefined byIconSizes
name
defines the icon typecolor
defines the icon color
If you’re new to TypeScript and you’re wondering what’s happening on line 7 and 11, hover over iconSizes
and you’ll see this:
keyof
In TypeScript, you can create types from JavaScript values. The [[keyof]](https://www.typescriptlang.org/docs/handbook/2/keyof-types.html)
operator takes an object type (IconSizes
on line 16) and returns a string or literal union of its keys:
iconSizes: string | number | symbol
typeof
TypeScript’s version of [typeof](https://www.typescriptlang.org/docs/handbook/2/typeof-types.html)
returns the types of the value of an object:
iconSizes: { small: number; medium: number; large: number; extraLarge: number; }
keyof typeof
keyof typeof indexes the keys of the object and returns a union of literal types:
iconSizes: "small" | "medium" | "large" | "extraLarge"
Now, thanks to the power of TypeScript, every time you use the size prop, your IDE will know what value should be provided and will display the options for you. To access autocomplete in VS Code on Mac, press ctrl and the spacebar simultaneously.
Let’s head back over to App.tsx
to test our new Icon
component.
import React from 'react'; import {SafeAreaView, StyleSheet, StatusBar} from 'react-native'; import {Text} from './components/Text'; // Import our icon component import {MaterialIcon} from './components/Icon'; const App = () => { return ( <> <StatusBar barStyle="dark-content" /> <SafeAreaView style={styles.container}> <Text>This font-weight is 'regular' </Text> <Text style={styles.boldFont}>This font-weight is 'bold' </Text> {/* Add icons here */} <MaterialIcon size="large" color="purple" name="home" /> <MaterialIcon size="extraLarge" color="black" name="github" /> </SafeAreaView> </> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, boldFont: { fontFamily: 'Nunito-Bold', }, }); export default App;
For demonstration purposes, I’ve added a home icon and the GitHub logo below the text with different sizes and colors.
Creating an icon button component in React Native
Buttons look great with icons, so let’s make one. For our button component, we’ll use the custom font that we built earlier with a new icon bundle.
In your components folder, create a new file called IconButton.tsx
:
cd components && touch IconButton.tsx && cd ..
Add the following code:
import React from 'react'; import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome'; import {Text} from './Text'; import {IconSizes, IconProps} from './Icon'; FontAwesomeIcon.loadFont(); type IconButtonProps = IconProps & { text: string; onPress: () => void; }; export const IconButton = ({ onPress, size, name, color, text, }: IconButtonProps) => ( <FontAwesomeIcon.Button onPress={onPress} name={name} size={IconSizes[size]} color={color}> <Text>{text}</Text> </FontAwesomeIcon.Button> );
If we want to use an icon from Material-UI Community Icons, we can import and use the icon component we built already. But this time, we’re going with Font Awesome’s icon bundle set, so we need to load the new icon bundle (line 6).
Now, let’s import our IconButton
into App.tsx
:
import React from 'react'; import {SafeAreaView, StyleSheet, StatusBar} from 'react-native'; import {Text} from './components/Text'; // Import our icon component import {MaterialIcon} from './components/Icon'; // Import our icon button component import { IconButton } from './components/IconButton'; const App = () => { return ( <> <StatusBar barStyle="dark-content" /> <SafeAreaView style={styles.container}> <Text>This font-weight is 'regular' </Text> <Text style={styles.boldFont}>This font-weight is 'bold' </Text> {/* Add icons here */} <MaterialIcon size="large" color="purple" name="home" /> <MaterialIcon size="extraLarge" color="black" name="github" /> {/* Add icon button here */} <IconButton onPress={() => {}} color="white" size="extraLarge" name="facebook" text="Login in with Facebook" /> </SafeAreaView> </> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, boldFont: { fontFamily: 'Nunito-Bold', }, }); export default App;
As with the MaterialIcon
component we built earlier, you can set the color, size, and icon type with the provided props.
Conclusion
In this article, we demonstrated how to add icons and fonts to your iOS or Android app. We also reviewed how to use the react-native-vector-icons library and shared how to troubleshoot an iOS auto-linking error.
It’s worth perusing the icons at the design stage of your app; there are some real gems in the icon bundle sets. If you’re looking for something specific, you should try lots of similar, descriptive keywords. For example, a search for “settings” will return a cog icon, but if you want an icon with multiple cogs, try searching “cogs.”
Now that you know how to customize your font, don’t be afraid to extend your text component with a nice font pairing — e.g., Nunito for headers and Roboto for paragraphs:
There you have it! You can customize your fonts and add icons to your heart’s content. Now go forth and build something amazing — just don’t use Vegan Style if you’re selling life insurance!
LogRocket: Instantly recreate issues in your React Native apps.

LogRocket is a React Native monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your React Native apps.
LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.
Start proactively monitoring your React Native apps — try LogRocket for free.