When you think of a typical website, it’s usually styled at the highest level with a header at the top, then a main section, then a footer at the bottom. What’s more, the header and footer typically remain constant as you navigate around the site and contain important navigational links. In React, we can provide client-side routing using the “react-router-dom” library, but keeping this structure takes a little bit of extra thought.
Using React-Router-Dom Library
To get us started, we need to understand the basic implementation of react-router-dom. This gets implemented in our root file, generally "index.js". First import the library, there are 3 functions from the library that are required for the basic routing function: BrowserRouter, Route, and NavLink. Now we will need to nest our top-level rendered component, we'll call it "Main" for now, within BrowserRouter. This is what gives us our ability to route between components.
// index.js
import {BrowserRouter, Route, NavLink} from 'react-router-dom';
import Main from './Components/Structure/Main';
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<Main />
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
To provide the routes, we will use the Route function from the react-router-dom library, one Route for each URL path we want to make available. We'll specify in each Route the URL path and what component should be rendered when that path is active. Let's make a few additional routes to demonstrate:
// index.js
import {BrowserRouter, Route, NavLink} from 'react-router-dom';
import Main from './Components/Structure/Main';
import About from './Components/About/About';
import Blog from './Components/Blog/Blog';
<BrowserRouter>
<Route exact path="/" component={Main} />
<Route exact path="/home" component={Main} />
<Route exact path="/about" component={About} />
<Route exact path="/blog" component={Blog} />
</BrowserRouter>
Here, our Main component will be rendered if a user navigates to the root URL "/" or "/home". If the user navigates to "/about", a new component called "About" will be rendered instead. Notice that I've had to import the new components into the Index.js file as well to make them available.
To provide the ability for a user to navigate, we'll want to set up NavLinks to each available route. Each NavLink will have a "to" attribute which specifies the URL that should be navigated to when the link is clicked. We may also want to add some styling. <NavLink to="/" exact style={Link} activeStyle={{background: "darkgreen"}}>Home</NavLink>
. I've set up my links on a separate component called Navbar to keep everything separated and clean, so now I can simply import Navbar to Index.js and add the component to the Router (because NavLinks do not work outside of the Router) and that will complete our basic implementation. Notice Navbar is not contained within a Route, this is because we want it to show up regardless of the URL. Now the user will see links that, when clicked, will navigate to different parts of the site.
// index.js
<Router>
<Navbar />
<Route exact path="/" component={Main} />
<Route exact path="/home" component={Main} />
<Route exact path="/about" component={AboutContainer} />
<Route exact path="/blog" component={BlogContainer} />
</Router>
Adding the Header/Footer
To add a Header and Footer, all we really need to do is add the components in place outside of the Router since they are not dependent on the URL path. But, since the Navbar will be rendered separately from the Header, it will look funky on the page without custom styling.
So to clean this up, we're going to pull the Navbar out of Index.js and add it to the Header component instead. Like the Navbar, we will not contain it within a Route. We'll also need to move the Header component into the Router now that it contains our NavLinks.
Now there are a lot of CSS tricks out there to get your Footer to stay on the bottom of your page. The way I've implemented it in my app is as follows, but feel free to explore other methods as well:
/* Set your default so that the sizing and placement is predictable */
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
/* Everything is a child of this node, so set its height to take up the full page or more, then set some padding at the bottom so your footer can slip into the gap. */
#root {
position: relative;
min-height: 100vh;
padding-bottom: 20px;
}
.Header {
position: relative;
height: 100px;
width: 100%;
}
.Main {
text-align: center;
position: relative;
}
/* Now set the height of your Footer equal to the padding that you left for it in your #root. To make it stay at the bottom, you will set it to be absolutely positioned. If Main grows larger, your Footer will move down to remain at the bottom of the page. */
.Footer {
height: 20px;
width: 100%;
position: absolute;
bottom: 0;
}
And we're done!
Now we have a constant Header at the top of the page, which contains our NavLinks, our URL-dependend content in the middle, and a constant Footer at the bottom.
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter as Router, Route, NavLink, Redirect, Switch} from 'react-router-dom';
import Header from './Components/Structure/Header';
import Main from './Components/Structure/Main';
import Footer from './Components/Structure/Footer';
import AboutContainer from './Components/About/AboutContainer';
import BlogContainer from './Components/Blog/BlogContainer';
ReactDOM.render(
<Router>
<Header/>
<Route exact path="/" component={Main} />
<Route exact path="/home" component={Main} />
<Route exact path="/about" component={AboutContainer} />
<Route exact path="/blog" component={BlogContainer} />
<Footer/>
</Router>
document.getElementById('root')
);
// Header.js
import React from 'react';
import Navbar from './Navbar';
const Header = () => {
return (
<div className="Header">
<Navbar />
</div>
)
}
export default Header;
Top comments (5)
Hey, sorry, what about the footer? how did you make to keep it in the bottom of the page?
Great question Javier! I didn't include the CSS styling since the scope was really about how to keep the header and footer on the page, regardless of which Route, but I've just added a suggested approach to help get the formatting to work.
would be great to see the Footer.js, and other code examples! maybe set up a link to github :)
So here's the thing....I quickly made the "site" for this write up based on a much larger, more complex real-life project, never made a github repo, and then somehow lost the local file 🤦
But the Footer.js file will be pretty simple. Something like:
If you really want to see more, you can check out my full project here. There's a lot there, but if you stick to the components in the structure folder, it should look pretty similar to this.
Hello, what about the new React style (NavLink, Outlet)? Can us import new style to this structure?