Search code examples
expoexpo-router

How to avoid duplicate header in expo-router?


I am having issues with duplicate headers and no idea how to fix.

Duplicate Headers Directory Tree

In layout 1 (root layout), I simply turn off headers for the (tabs) route:

<Stack>
    <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
    ...
</Stack>

In layout 2 (tabs layout), I keep headers on for all screens and assign them a title (which is displayed in the first "layer" of headers):

<Tabs>
    <Tabs.Screen
        name="websites"
            options={{
                title: "Websites",
            }}
        />
    </Tabs>

In layout 3 (sub-route layout, e.g. for "websites"),

  • I turn headers off for the index route (e.g. "/websites") so I don't see duplicate headers there, and
  • I turn it on for the parametrized route (e.g. "/websites/[website]"):
<Stack>
    <Stack.Screen
        name="index"
        options={{
            headerShown: false
        }}
    />
    <Stack.Screen
        name="[website]"
        options={{ headerTitle: "Website" }}
    />
</Stack>

I am aware that the syntax varies and I have Tabs.Screen in one layout and Stack.Screen in another, but I'd assume they both manipulate the same object.

What happens is that

  • layout 2 adds a header for each screen, and
  • layout 3 adds another header for the parametrized route screen (the one with the back button).

For example on iOS, instead the "Website" header pushing "Websites" to the left for displaying a specific "Website", it simply displays the second header underneath.

  • I could turn off headers in layout 2 where I have a layout 3, but it would cause inconsistencies. So I can't imagine that's correct.
  • I also need layout 3 to prevent the parametrized route from showing up as tab.

What would be the correct way to configure this?


Solution

  • I believe this is the expected behavior for layouts. Layouts are nested inside one another and they show their own headers.

    If you have Tabs -> Stacks layouts, there will be two headers shown by default.

    Modifying {headerShown: boolean} will only turn on/off header for current layout, it won't affect the outer layouts.

    So when u set {headerShown: false} inside <Stack.Screen name="index" />, it only hide the Stack's header, not the one from tabs.