RoyalZSoftware
Back to Blog

How I built a custom header for react navigation

Unknown 2023-06-18 4 min read
How I built a custom header for react navigation

I want to share my insights on how to integrate a custom header in a React native application.

Why bother with custom headers anyway?

Differentiate yourself; don't be stuck in a Matrix. ESCAPE FROM THE MATRIX!!!11!.

Aside from the obvious Joke, there are many valid reasons why you would want to have Custom Header. Here are some of the more obvious Reasons:

How do I start?

  1. Initialize your React Native App

    npx react-native init MyApp --template react-native-template-typescript
  2. Install the required dependencies

    cd MyApp
    npm install @react-navigation/native @react-navigation/native-stack
    npx pod-install

Create the header component

I have chosen to develop a straightforward header component for this blog, offering the flexibility to include Icons on either side and a central title. The component will have a transparent background.

Before moving forward with the implementation, it is important to note that this blog post does not provide a 1:1 Implementation guide, but rather presents a possible approach to creating a custom header. Its purpose is to provide guidance and help readers gain a better understanding of the implementation process.

type CustomHeaderProps = {
    leftIcon?: SvgProps;
    rightIcon?: SvgProps;
    title: string;
}

The icon component

To utilize our custom icons, we require a component that enables us to render our icons and assign click functionality to them.

import React from 'react';
import { TouchableOpacity } from 'react-native';
import Svg, { SvgProps } from 'react-native-svg';
 
interface IconProps extends SvgProps {
  onPress?: () => void;
}
 
const ClickableIcon: React.FunctionComponent<IconProps> = ({
  onPress,
  ...svgProps
}) => {
  return (
    <TouchableOpacity onPress={onPress}>
      <Svg {...svgProps} />
    </TouchableOpacity>
  );
};

With our types defined and all the necessary Components at our disposal, it's time to create a FunctionComponent for our CustomHeader. In this example, we will include two Icons that will serve as navigation buttons, directing the user to a page named "Friends" within our RootStackParams.

const CustomHeader: React.FunctionComponent<CustomHeaderProps> = ({ title, left, right }) => {
  const navigation = useNavigation();
  const handleSvgClick = () => {
    navigation.navigate('Friends', { uid: 1 })
  }
 
  const leftIcon = (leftIcon &&
    <ClickableIcon onPress={handleSvgClick}>
        {leftIcon}
    </ClickableIcon>
  );
 
  const rightIcon = (right &&
    <ClickableIcon onPress={handleSvgClick}>
        {rightIcon}
    </ClickableIcon>
  );
 
  return (
    <View>
      <>{leftIcon}</>
      <Text>{title}</Text>
      <>{rightIcon}</>
    </View>
  )
}
 
export default CustomHeader;

Additionally, we have encapsulated our icons within view tags to ensure that our title always stays centered, regardless of the presence or absence of icons.

We have also applied several other style rules to enhance the overall visual appeal of our fancy header.

 
...
  return (
    <View style={styles.container}>
      <View>{leftIcon}</View>
      <Text style={styles.text}>{title}</Text>
      <View>{rightIcon}</View>
    </View>
  )
}
 
const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    backgroundColor: 'transparent',
    paddingHorizontal: 16,
    marginTop: 16,
    height: 80,
  },
  text: {
    color: 'white',
    textAlign: 'center',
    fontFamily: 'Lato-Bold',
    fontSize: 24,
  }
}

Telling the Stack Navigator about it

The react-navigation stack navigator needs to know what header to use, or it will fall back to the default one.

import { createStackNavigator } from '@react-navigation/stack';
import Header from '@components/CustomHeader';
 
const Stack = createStackNavigator();
 
function MyStack() {
  const friends = <MySvg/>
  return (
    <Stack.Navigator>
      <Stack.Screen 
        name="Home" 
        component={Home} 
        option={{
          header: () => (
            <CustomHeader title="Home" leftIcon={friends} rightIcon={friends} />
          ),
        }}
      />
    </Stack.Navigator>
  );
}

Full code snippet

import React from 'react';
import { TouchableOpacity } from 'react-native';
import Svg, { SvgProps } from 'react-native-svg';
 
type CustomHeaderProps = {
    leftIcon?: SvgProps;
    rightIcon?: SvgProps;
    title: string;
}
 
interface IconProps extends SvgProps {
  onPress?: () => void;
}
 
const ClickableIcon: React.FunctionComponent<IconProps> = ({
  onPress,
  ...svgProps
}) => {
  return (
    <TouchableOpacity onPress={onPress}>
      <Svg {...svgProps} />
    </TouchableOpacity>
  );
};
 
const CustomHeader: React.FunctionComponent<CustomHeaderProps> = ({ title, left, right }) => {
  const navigation = useNavigation();
  const handleSvgClick = () => {
    navigation.navigate('Friends', { uid: 1 })
  }
 
  const leftIcon = (leftIcon &&
    <ClickableIcon onPress={handleSvgClick}>
        {leftIcon}
    </ClickableIcon>
  );
 
  const rightIcon = (right &&
    <ClickableIcon onPress={handleSvgClick}>
        {rightIcon}
    </ClickableIcon>
  );
 
    return (
    <View style={styles.container}>
      <View>{leftIcon}</View>
      <Text style={styles.text}>{title}</Text>
      <View>{rightIcon}</View>
    </View>
  )
}
 
const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    backgroundColor: 'transparent',
    paddingHorizontal: 16,
    marginTop: 16,
    height: 80,
  },
  text: {
    color: 'white',
    textAlign: 'center',
    fontFamily: 'Lato-Bold',
    fontSize: 24,
  }
}
 
export default CustomHeader

Conclusion

Custom headers are crucial for enhancing the user experience and visual appeal of mobile applications. Additionally, they can provide functionality like search bars or user profile information.

More articles

Building a Web Server in Go: A Beginner's Guide

Building a Web Server in Go: A Beginner's Guide

Oleksandr Vlasov 2024-11-26 3 min read
React Hooks — createContext, useContext, useMemo

React Hooks — createContext, useContext, useMemo

Oleksandr Vlasov 2024-10-23 4 min read
Mastering Git Rebase Interactive: Squashing Commits for a Clean History

Mastering Git Rebase Interactive: Squashing Commits for a Clean History

Alexander Panov 2024-10-21 2 min read