To correctly use a Button component as a link in React, we need to override the underlying button
HTML tag of the component and turn it into an anchor
tag, while still keeping the component styles and behaviour intact.
Let's explore in more detail.
Button component
First, let's build a typical Button
component in React:
const Button = ({ onClick, children }) => {
return (
<button onClick={onClick} className="button">{children}</button>
)
};
export default Button
And add some styles to it:
.button {
background-color: #4CAF50;
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
}
Now, to use it, all we need to do is the following:
import Button from './Button'
const ComponentWithButton = () => {
const handleClick = () => {
// Some button logic
}
return (
... other JSX
<Button onClick={handleClick}>Button</Button>
)
}
This looks great so far! But what happens if we need to use this component not as a button, but as a link to another page or website?
Our first instinct might be to handle the navigation logic using the onClick
handler. This is the wrong approach! Here's why:
- The HTML of our page should be semantic - HTML elements have a specific purpose and should be used accordingly - a
button
should change something on the page whileanchor
tags are used for navigation; - Using the correct HTML tags is also good for accessibility - assistive technology benefits greatly from semantic HTML and so do users who navigate our website via keyboard;
- Search engines take advantage of the links on our website to crawl it, so opting for an
anchor
tag is also SEO friendly.
So, if it's not recommended to use the onClick
handler for navigation, what is the alternative?
Introducing React's as
prop pattern
There is a mechanism to override the underlying HTML tag of our button component and to turn it into a link. Let's introduce an as
prop to our Button
component:
const Button = ({ onClick, children, as: Component = "button", ...rest }) => {
return (
<Component onClick={onClick} className="button" {...rest}>
{children}
</Component>
);
};
Handle external links
With the help of the as
prop, we can easily turn our button into a link:
import Button from './Button'
const ComponentWithLink= () => {
return (
... other JSX
<Button as="a" href="https://blog.whereisthemouse.com">Where is the mouse?</Button>
)
}
The component above looks identical to our normal button, but is semantically a link. This is exactly what we wanted! ๐
๐ก Note: Our button is actually a link now. Because of this, there are some subtle differences it its behaviour. For example, if we use the keyboard to focus on a button, we can activate it with both Enter
and Space
key, while for a link only Enter
will work.
Handle internal links
Here's another scenario! What if we are using a router like React Router and want to link to a page that is internal to our website? Luckily, our component easily allows for this implementation:
import { Link } from 'react-router-dom"
import Button from './Button'
const ComponentWithInternalLink= () => {
return (
... other JSX
<Button as={Link} to="/">Home</Button>
)
}
Once again, our component is styled exactly like a button but it is a React Router link underneath!
Conclusion
Let's conclude this article on a note of caution!
The approach above works nicely to convert our buttons into real semantic links. But before we use it, it is important to take a step back and consider whether this is something that we really want or need in the context of our React app.
While there are legitimate reasons for creating links that look and feel like buttons, in the majority of cases, we are better off using our React components and HTML elements as originally intended.
Happy coding! โจ