Navigation Options

Headers, Titles and Navigation Options

Options come from three places: a navigator's screenOptions (all its screens), a layout's Stack.Screen options (one screen), and the screen itself while it renders, the only place that knows the data. BookNest's book screen titles itself with the book's name and adds a share button that reuses shareBook() from Sharing a Book from BookNest:

src/app/book/[id].tsx: options set from the screen's own data (excerpt)XML
    <ScrollView contentContainerStyle={{ padding: 16, gap: 12 }}>
      <Stack.Screen options={{
        title: book.title,
        headerRight: () => <Ionicons name="share-social-outline" size={24} color="#1565c0"
          accessibilityLabel="Share" onPress={() => shareBook(book)} />,
      }} />

A <Stack.Screen> rendered inside a screen draws nothing; it passes its options up to the navigator, and it is the Expo Router 6,418 spelling of React Navigation 407,918 's navigation.setOptions(). The layout sets title: '' for this route: the default title is the route name, so the header would otherwise show book/[id] until the screen renders. The right side of the figure in Stacks, Tabs, Drawers shows the result. The options you will use most:

Common screen options in Expo Router and React Navigation
Option Effect
title, headerTitle Text, or a component, in the header
headerShown false hides the header, for a screen that draws its own
headerLeft, headerRight Buttons beside the title
headerStyle, headerTintColor Background; color of title, arrow and buttons
presentation card, modal, transparentModal, formSheet
tabBarBadge, tabBarIcon, drawerLabel Tab and drawer entries

Native-stack headers are platform views (an Android toolbar, an iOS UINavigationBar), so a custom header: () => ... gives up some native behavior. Give icon-only header buttons an accessibilityLabel, as the share button has, and a touch target of about 48 dp, Android's recommended minimum (Accessibility and i18n).