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.
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
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 asset/fonts
Head over to Google Fonts to download the 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 nearly 13,000 free icons and 14.5k 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 && cd ios && pod install && cd ..
This will install the library and dev dependency. Navigate to your iOS folder, install your project’s CocoaPods
, then navigate back to your project folder.
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
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 VSCode on Mac, press ctrl and spacebar together.
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
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
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: Full visibility into your web apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
Try it for free.