Adding a Link to a Bootstrap Button with React Router

While working on my React based portfolio website recently, I ran into an issue regarding buttons and links. I had designed a section of the website that had several buttons, each needing to link to a different url like “/about” or “/work”, and so I tried to come up with what I thought was the simplest solution.

I installed React Router, set up some basic routing in my App.js component, and used the following code to setup my buttons as React Router Links. (Note that I’m simplifying the Bootstrap options I used for demo purposes)

import { Link } from “react-router-dom”;
import Button from "react-bootstrap/Button";
...<Link to="/about">
<Button variant="outline-light" size="lg">
about
</Button>
</Link>

While this code technically worked and linked to the page I wanted, it wasn’t ideal for two reasons. The first issue was that it added a blue underline to the button text while hovering. While this can be fixed using CSS, it isn’t ideal.

The next issue is that this actually doesn’t produce valid HTML, because you are not supposed to wrap an a tag around a button. This Stack Overflow post explains it well. For further reference, here’s what the React button will look like in HTML form after the JSX is transpiled:

<a href="/about">
<button type="button" class="btn">
about
</button>
</a>

The Solutions

There are two good solutions to this that I found. The first, and the one that I ultimately went with, is to use hooks. Even if you’re not yet familiar with React Hooks, I promise this will be easy to implement.

React Router now comes with some built in hooks that according to their documentation “let you access the state of the router and perform navigation from inside your components.” Note: you must be using React 16.8 or higher to use these hooks.

The hook we will be using for the button is called useHistory

Here’s a look at the code that I used, which I was able to match pretty closely to the example used in the React Router docs.

import { useHistory } from "react-router-dom";
import Button from "react-bootstrap/Button";
...function HomeSectionMain() {
const history = useHistory();
function handleClick(path) {
history.push(path);
}
return (
<Button
variant="outline-light"
size="lg"
onClick={() => handleClick("about")}
>
about
</Button>
)
}

I chose this solution because using hooks allowed my component to be more lightweight, while creating valid HTML as seen below:

<button
type="button"
class="btn btn-outline-light btn-lg"
>
about
</button>

While the previous solution worked great for me, there is another solution I came across on Stack Overflow as well. This option styles the <Link> to match the button style, which has the advantage of being more semantic, and doesn’t require you to add an extra clickHandler() function.

Here is an example of this code works:

<Link 
className="btn btn-outline-light btn-lg"
role="button"
to="/about"
>
about
</Link>

It can complicate things on the CSS side if you’re not careful though, as one user points out “applying an existing CSS class designed for a <button/> to an <a/> can lead to broken style. The reason is that these elements are fundamentally different in terms of CSS behavior, see this question.”

I hope these options can help others who run into similar issues, and if you have any other interesting ways of solving this let me know in the comments below, thanks!

Software Developer and Video/Post Production Professional. Recent graduate of Flatiron School.