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-svgFor rendering .svg
s, 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 iconLet'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:
import { Svg, Path } from 'react-native-svg'
- replace
svg
andpath
withSvg
andPath
- add a default
fill
color to thesvg
- add a default
width
andheight
to thesvg
It should end up looking something like this:
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:
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 tabWe 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:
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:
<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
:
colorBlue: '#1D84B5',colorGrey: '#8E9AAF',
And let's use them for the tint colours in 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 titleWhile 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.