Reputation: 121
Using React-Router is there a way manage nested routes that overlay on top of the original route navigation?
I went through the react-router documentation but had trouble finding an example where the original navigation links were removed or hidden on the page.
I'm looking for an example like the below image:
I'm trying to have each tab in the above image be represented by a unique route, and then when a user clicks on an element under a tab, the element's detailed view would show overtop the entire page beneath the app's header. To me, a nested route seems to make sense in this scenario, however, the nested route puts the detailed component beneath the tabbed component. Which is not the user experience I'm looking for.
The routes that I believe make sense given the above would be something like:
Tabs:
/overview/tab1
/overview/tab2
/overview/tab3
Detailed View of Elements:
/overview/tab1/elements/:elementNumber
I was able to achieve this using the following:
export function Navigation() {
return (
<div>
<Switch>
<Route path="/tabs">
<TabbedNavigation />
</Route>
<Route path="/details">
<DetailedNavigation />
</Route>
</Switch>
</div>
);
}
export function TabbedNavigation() {
return (
<>
<Switch>
<Route path="/tabs/tab1">
<Tab1 />
</Route>
<Route path="/tabs/tab2">
<Tab2 />
</Route>
<Route path="/tabs/tab3">
<Tab3 />
</Route>
</Switch>
</>
);
}
export function DetailedNavigation() {
return (
<>
<Switch>
<Route path="/details/elements/:elementNumber">
<ElementDetails />
</Route>
</Switch>
</>
);
}
The above works fine, and provides the user experience I'm looking to achieve, but I feel like there has to be a better way to achieve the same using the react-router api.
Is it possible to have overplayed routes using react-router?
Upvotes: 4
Views: 1166
Reputation: 163
Using the Outlet component from react-router-dom might be the way to go. You can easily render the <Outlet />
component in the parent in the place you want.
In the case of the element detail, you could do something like:
function Parent() {
const location = useLocation()
if (location.pathname === childPath) return <Outlet />
return (
<ParentRenderStuff />
)
}
Upvotes: 0
Reputation: 2020
You need to wrap the elements that needs to be overwritten within switch
const TabMenu = () => (
<div >
<Link to="/tabs/tab1">Tab1</Link> <span> </span>
<Link to="/tabs/tab2">Tab2</Link> <span> </span>
<Link to="/tabs/tab3">Tab3</Link>
</div>)
export function Navigation() {
return (
<div>
<Switch>
<Route path="/tabs">
<TabMenu/>
<TabbedNavigation />
</Route>
<Route path="/details/elements/:elementNumber">
<DetailedNavigation />
</Route>
</Switch>
</div>
);
}
Because the TabMenu are inside Switch element, it will get replaced with Detailed View.
Here is working code example
https://codesandbox.io/s/react-router-full-page-for-nested-route-s15rx?file=/src/App.js
Upvotes: 1
Reputation: 20785
You can achieve that with CSS, set the green container with a position: "relative"
style, and the detail view with position: "absolute"
and left
, right
, top
, bottom
to 0
. With this, the details view will cover all other contents of the green container since it gets positioned relative to its closest positioned ancestor (the first ancestor with a position attr)
<GreenContainer style={{ position: "relative" }}>
...
<DetailsView
style={{
position: "absolute",
top: 0,
bottom: 0,
right: 0,
left: 0,
}}
>
...
Here is a codesandbox I set up with the example of nested routes provided in the react-router documentation
https://codesandbox.io/s/react-router-typescript-demo-forked-n0woz?file=/src/example.tsx
note: I'm assuming the green container is a sibling of the header
Upvotes: 1