Skip to main content

Vector Icons

The main advantage of using svg - Scalable Vector Graphics - is that they are scalable as the name suggests. This means that the same vector image will look absolutely crisp on any size display. This is extremely appealing when building mobile applications, because we need to consider support for devices with all kinds of pixel density. You will also be able to change the color of the icon dynamically, without needing to create several versions of the icon.

Let's use vector icons for our home, history and analytics tabs.

I've chosen the Home and List and Analytics icons from FlatIcon.

Install react-native-svg#

For rendering .svgs, we will use react-native-svg.

First, install the library:

yarn add react-native-svg# ornpm install react-native-svg

Then, install the iOS native dependencies:

cd ios && pod install && cd ..

And finally, rebuild your app from XCode / Android Studio / terminal.

Adding an .svg icon#

Let's, create a Icons.tsx component in your /components directory.

Take this svg file:

<svg width="511pt" height="511pt" viewBox="0 1 511 511.999">  <path d="M498.7 222.695c-.016-.011-.028-.027-.04-.039L289.805 13.81C280.902 4.902 269.066 0 256.477 0c-12.59 0-24.426 4.902-33.332 13.809L14.398 222.55c-.07.07-.144.144-.21.215-18.282 18.386-18.25 48.218.09 66.558 8.378 8.383 19.44 13.235 31.273 13.746.484.047.969.07 1.457.07h8.32v153.696c0 30.418 24.75 55.164 55.168 55.164h81.711c8.285 0 15-6.719 15-15V376.5c0-13.879 11.293-25.168 25.172-25.168h48.195c13.88 0 25.168 11.29 25.168 25.168V497c0 8.281 6.715 15 15 15h81.711c30.422 0 55.168-24.746 55.168-55.164V303.14h7.719c12.586 0 24.422-4.903 33.332-13.813 18.36-18.367 18.367-48.254.027-66.633zm-21.243 45.422a17.03 17.03 0 01-12.117 5.024H442.62c-8.285 0-15 6.714-15 15v168.695c0 13.875-11.289 25.164-25.168 25.164h-66.71V376.5c0-30.418-24.747-55.168-55.169-55.168H232.38c-30.422 0-55.172 24.75-55.172 55.168V482h-66.71c-13.876 0-25.169-11.29-25.169-25.164V288.14c0-8.286-6.715-15-15-15H48a13.9 13.9 0 00-.703-.032c-4.469-.078-8.66-1.851-11.8-4.996-6.68-6.68-6.68-17.55 0-24.234.003 0 .003-.004.007-.008l.012-.012L244.363 35.02A17.003 17.003 0 01256.477 30c4.574 0 8.875 1.781 12.113 5.02l208.8 208.796.098.094c6.645 6.692 6.633 17.54-.031 24.207zm0 0" /></svg>

and convert it into a React component. To do this:

  1. import { Svg, Path } from 'react-native-svg'
  2. replace svg and path with Svg and Path
  3. add a default fill color to the svg
  4. add a default width and height to the svg

It should end up looking something like this:

src/components/Icons.tsx
import React from 'react';import { Svg, Path } from 'react-native-svg';
export const HomeIcon: React.FC = () => {  return (    <Svg width={40} height={40} viewBox="0 1 511 511.999" fill="teal">      <Path d="M498.7 222.695c-.016-.011-.028-.027-.04-.039L289.805 13.81C280.902 4.902 269.066 0 256.477 0c-12.59 0-24.426 4.902-33.332 13.809L14.398 222.55c-.07.07-.144.144-.21.215-18.282 18.386-18.25 48.218.09 66.558 8.378 8.383 19.44 13.235 31.273 13.746.484.047.969.07 1.457.07h8.32v153.696c0 30.418 24.75 55.164 55.168 55.164h81.711c8.285 0 15-6.719 15-15V376.5c0-13.879 11.293-25.168 25.172-25.168h48.195c13.88 0 25.168 11.29 25.168 25.168V497c0 8.281 6.715 15 15 15h81.711c30.422 0 55.168-24.746 55.168-55.164V303.14h7.719c12.586 0 24.422-4.903 33.332-13.813 18.36-18.367 18.367-48.254.027-66.633zm-21.243 45.422a17.03 17.03 0 01-12.117 5.024H442.62c-8.285 0-15 6.714-15 15v168.695c0 13.875-11.289 25.164-25.168 25.164h-66.71V376.5c0-30.418-24.747-55.168-55.169-55.168H232.38c-30.422 0-55.172 24.75-55.172 55.168V482h-66.71c-13.876 0-25.169-11.29-25.169-25.164V288.14c0-8.286-6.715-15-15-15H48a13.9 13.9 0 00-.703-.032c-4.469-.078-8.66-1.851-11.8-4.996-6.68-6.68-6.68-17.55 0-24.234.003 0 .003-.004.007-.008l.012-.012L244.363 35.02A17.003 17.003 0 01256.477 30c4.574 0 8.875 1.781 12.113 5.02l208.8 208.796.098.094c6.645 6.692 6.633 17.54-.031 24.207zm0 0" />    </Svg>  );};

Finally, in order so support arbitrary colors of the icon, pass the color in as a prop:

src/components/Icons.tsx
type IconProps = {  color?: string;  size?: number;};
export const HomeIcon: React.FC<IconProps> = ({  color = 'teal',  size = 40,}) => {  return (    <Svg width={size} height={size} viewBox="0 1 511 511.999" fill={color}>---

Use the icon in the bottom tab#

We can customize the style of the bottom tab - including the name and icons - using the screenOptions prop on the Tab Navigator.

Open BottomTabs.navigator.tsx and use the screenOptions prop to return the HomeIcon on the first tab, and the ListIcon on the second tab.

Start by just rendering out the route name:

import { Text } from 'react-native';
<BottomTabs.Navigator  screenOptions={({ route }) => ({    tabBarIcon: ({ color, size }) => {      return <Text>{route.name}</Text>;    },  })}>

Next, render the correct icon based on the route selected:

src/screens/BottomTabs.navigator.tsx
import { HomeIcon } from '../components/Icons';
<BottomTabs.Navigator  screenOptions={({ route }) => ({    tabBarIcon: ({ color, size }) => {      if (route.name === 'Home') {        return <HomeIcon />;      }
      if (route.name === 'History') {        return <Text>History</Text>;      }
      if (route.name === 'Analytics') {        return <Text>Analytics</Text>;      }
      return null;    },  })}>

Finally, pass through the color and size args to the icon:

src/screens/BottomTabs.navigator.tsx
<BottomTabs.Navigator  screenOptions={({ route }) => ({    tabBarIcon: ({ color, size }) => {      if (route.name === 'HomeTab') {-        return <HomeIcon />;+        return <HomeIcon color={color} size={size} />;      }      if (route.name === 'HistoryTab') {        return <ListIcon color={color} size={size} />;      }      if (route.name === 'AnalyticsTab') {        return <AnalyticsIcon color={color} size={size} />;      }      return null;    },  })}>

To customise the color of the tab bar icon, use tabBarActiveTintColor and tabBarInactiveTintColor.

Let's add two new colours to our theme.ts:

src/theme.ts
colorBlue: '#1D84B5',colorGrey: '#8E9AAF',

And let's use them for the tint colours in BottomTabs.navigator.tsx

src/screens/BottomTabs.navigator.tsx
<BottomTabs.Navigator  screenOptions={({ route }) => ({    tabBarActiveTintColor: theme.colorBlue,    tabBarInactiveTintColor: theme.colorGrey,    tabBarIcon: ({ color, size }) => {

Let's also hide the tab bar label with:

tabBarShowLabel: false,

Updating tab title#

While we're here, let's also update the titles of the tabs:

<BottomTabs.Screen  name="Home"  component={Home}+  options={{ title: "Today's Mood" }}/><BottomTabs.Screen  name="History"  component={History}+  options={{ title: 'Past Moods' }}/><BottomTabs.Screen  name="Analytics"  component={Analytics}+  options={{ title: 'Fancy Charts' }}/>
tip

If you have lots of icons to convert, instead of converting them manually you can use react svgr - an online tool that can not only convert your svg to a React component, but it also cleans the svg from unnecessary <g>s and translations.

iOS bottom tabsAndroid bottom tabs