ExpoStartup

Header

A customizable navigation header component with support for back buttons, title, and action items.

Header

The Header component provides a consistent navigation bar for your application screens with customizable elements and theming support.

Import

import Header, { HeaderIcon } from '@/components/Header';

Features

  • Customizable Content: Title, back button, and support for custom components
  • Right Action Items: Multiple buttons or controls on the right side
  • Collapsible Animation: Optional collapsible behavior for scrolling content
  • Theming Support: Automatically adapts to light/dark mode
  • Custom Styling: Accepts additional Tailwind classes
  • Header Icons: Built-in HeaderIcon component for navigation and action buttons

Props

Header Component

PropTypeDefaultDescription
titlestringText to display as the header title
showBackButtonbooleanfalseWhether to show a back button
onBackPress() => voidCustom action for the back button
rightComponentsReact.ReactNode[][]Components to display on the right side
leftComponentReact.ReactNodeCustom component for the left side
middleComponentReact.ReactNodeCustom component for the center
collapsiblebooleanfalseWhether the header should animate on scroll
visiblebooleantrueControls visibility when collapsible is true

HeaderIcon Component

PropTypeDefaultDescription
hrefstringNavigation link
iconIconNameRequiredName of the icon to display
hasBadgebooleanfalseWhether to show a notification badge
onPressFunctionCustom press handler

Basic Usage

// Basic header with title
<Header title="Home" />
 
// Header with back button
<Header 
  title="Details" 
  showBackButton 
/>
 
// Header with action icons
<Header 
  title="Messages" 
  rightComponents={[
    <HeaderIcon key="search" icon="Search" href="/search" />,
    <HeaderIcon key="settings" icon="Settings" href="/settings" />
  ]}
/>

Usage Examples

Basic Header with Title

<Header title="Home" />

Header with Back Button

<Header 
  title="Product Details" 
  showBackButton={true} 
/>

Header with Right Action Icons

<Header 
  title="Messages" 
  showBackButton={true}
  rightComponents={[
    <HeaderIcon key="search" href="/search" icon="Search" />,
    <HeaderIcon key="notifications" href="/notifications" icon="Bell" hasBadge={true} />
  ]}
/>

Collapsible Header

function CollapsibleHeaderScreen() {
  const [headerVisible, setHeaderVisible] = useState(true);
  const scrollY = useRef(new Animated.Value(0)).current;
  
  const handleScroll = Animated.event(
    [{ nativeEvent: { contentOffset: { y: scrollY } } }],
    { useNativeDriver: true }
  );
  
  useEffect(() => {
    const listener = scrollY.addListener(({ value }) => {
      // Hide header when scrolling down, show when scrolling up
      setHeaderVisible(value <= 0 || value < previousScrollY.current);
      previousScrollY.current = value;
    });
    
    return () => {
      scrollY.removeListener(listener);
    };
  }, [scrollY]);
  
  return (
    <View className="flex-1">
      <Header 
        title="Collapsible Header" 
        showBackButton={true}
        collapsible={true}
        visible={headerVisible}
      />
      
      <Animated.ScrollView
        onScroll={handleScroll}
        scrollEventThrottle={16}
        contentContainerStyle={{ paddingTop: 70 }} // Add padding for the header
      >
        {/* Content */}
      </Animated.ScrollView>
    </View>
  );
}

Custom Header with Middle Component

<Header
  showBackButton={true}
  middleComponent={
    <View className="flex-row items-center">
      <Image 
        source={require('../assets/logo.png')} 
        className="w-8 h-8 mr-2" 
      />
      <Text className="text-lg font-bold">Brand Name</Text>
    </View>
  }
  rightComponents={[
    <HeaderIcon key="menu" href="#" icon="Menu" onPress={() => openDrawer()} />
  ]}
/>

Profile Screen Example

function ProfileScreen() {
  return (
    <View className="flex-1">
      <Header 
        title="Profile" 
        rightComponents={[
          <HeaderIcon key="settings" href="/settings" icon="Settings" />,
          <HeaderIcon key="edit" href="/edit-profile" icon="Edit" />
        ]}
      />
      
      <ScrollView className="flex-1 pt-4">
        <View className="items-center mb-6">
          <Avatar 
            source={{ uri: 'https://example.com/avatar.jpg' }} 
            size="xl"
          />
          <Text className="text-xl font-bold mt-2">John Doe</Text>
          <Text className="text-gray-500">john.doe@example.com</Text>
        </View>
        
        <Section title="Account Information">
          {/* Account Information */}
        </Section>
        
        <Section title="Settings">
          {/* Settings */}
        </Section>
      </ScrollView>
    </View>
  );
}

E-commerce Header Example

function ProductListingScreen() {
  return (
    <View className="flex-1">
      <Header 
        leftComponent={
          <Icon name="Menu" size={24} onPress={() => openFilters()} />
        }
        middleComponent={
          <View className="bg-gray-100 dark:bg-gray-800 rounded-full px-4 py-2 w-full max-w-[220px] flex-row items-center">
            <Icon name="Search" size={18} className="mr-2 text-gray-500" />
            <TextInput 
              placeholder="Search products..." 
              className="flex-1 text-sm" 
              placeholderTextColor="gray" 
            />
          </View>
        }
        rightComponents={[
          <HeaderIcon key="wishlist" href="/wishlist" icon="Heart" />,
          <HeaderIcon key="cart" href="/cart" icon="ShoppingBag" hasBadge={cartItems.length > 0} />
        ]}
      />
      
      {/* Product listing content */}
    </View>
  );
}

Chat Header Example

function ChatScreen({ contact }) {
  return (
    <View className="flex-1">
      <Header 
        showBackButton={true}
        leftComponent={
          <View className="flex-row items-center ml-2">
            <Avatar source={{ uri: contact.avatar }} size="sm" />
            <View className="ml-2">
              <Text className="font-bold">{contact.name}</Text>
              <Text className="text-xs text-gray-500">
                {contact.online ? 'Online' : 'Offline'}
              </Text>
            </View>
          </View>
        }
        rightComponents={[
          <HeaderIcon key="call" href="#" icon="Phone" onPress={() => startCall()} />,
          <HeaderIcon key="more" href="#" icon="MoreVertical" onPress={() => openOptions()} />
        ]}
      />
      
      {/* Chat content */}
    </View>
  );
}

Best Practices

Consistent Header Style

Maintain a consistent header style throughout your application:

// Define standard header configurations
const headers = {
  main: { title: "App Name" },
  section: (title) => ({ title, showBackButton: true }),
  detail: (title) => ({ 
    title, 
    showBackButton: true,
    rightComponents: [
      <HeaderIcon key="share" href="#" icon="Share" onPress={() => share()} />
    ]
  })
};
 
// Use them consistently
<Header {...headers.main} />
<Header {...headers.section("Products")} />
<Header {...headers.detail("Product Details")} />

HeaderIcon Usage

Use HeaderIcon components consistently for action items:

// Good: Consistent use of HeaderIcon
<Header 
  title="Products"
  rightComponents={[
    <HeaderIcon key="filter" icon="Filter" onPress={() => openFilters()} />,
    <HeaderIcon key="sort" icon="SortAsc" onPress={() => openSorting()} />
  ]}
/>
 
// Avoid: Mixing HeaderIcon with custom components
<Header 
  title="Products"
  rightComponents={[
    <HeaderIcon key="filter" icon="Filter" onPress={() => openFilters()} />,
    <TouchableOpacity onPress={() => openSorting()}>
      <Text>Sort</Text>
    </TouchableOpacity>
  ]}
/>

Collapsible Header Management

When using collapsible headers, ensure proper content padding:

function CollapsibleScreen() {
  // Header visibility state and scroll handling logic here
  
  return (
    <View className="flex-1">
      <Header 
        title="Feed"
        collapsible={true}
        visible={headerVisible}
      />
      
      <Animated.FlatList
        data={items}
        renderItem={renderItem}
        onScroll={handleScroll}
        scrollEventThrottle={16}
        contentContainerStyle={{ 
          paddingTop: 70, // Account for header height
          paddingHorizontal: 16
        }}
      />
    </View>
  );
}

Implementation Details

The Header component is built with React Native's View and TouchableOpacity components, utilizing Tailwind CSS for styling. It supports both static and animated behaviors through the use of the Animated API.

For collapsible headers, the component uses Animated.spring and Animated.timing to create smooth translation and opacity animations based on the visible prop.

The component automatically adapts to the current theme using the useThemeColors hook, ensuring proper appearance in both light and dark modes.

The HeaderIcon subcomponent provides a standardized way to add action buttons to the header, with built-in support for navigation links via Expo Router and notification badges.

Notes

  • When using collapsible headers, remember to add appropriate padding to your scrollable content
  • The header uses the z-index to ensure it appears above other content
  • For custom header layouts, you can use the leftComponent and middleComponent props
  • The HeaderIcon component can be used independently for consistent icon buttons
  • Back button behavior defaults to router.back() but can be customized with the onBackPress prop