Wrapping a react-router Link in an html button

Using suggested method: This is the result: A link in the button, Code in between comment lines

I was wondering if there is a way to wrap a Link element from 'react-router' in an HTML button tag using react.

I currently have Link components to navigate pages in my app, but I would like to map that functionality to my HTML buttons.

enter image description here enter image description here


Solution 1:

While this will render in a web browser, beware that:
⚠️Nesting an html button in an html a (or vice-versa) is not valid html ⚠️. If you want to keep your html semantic to screen readers, use another approach.

Do wrapping in the reverse way and you get the original button with the Link attached. No CSS changes required.

 <Link to="/dashboard">
     <button type="button">
          Click Me!
     </button>
 </Link>

Here button is HTML button. It is also applicable to the components imported from third party libraries like Semantic-UI-React.

 import { Button } from 'semantic-ui-react'
 ... 
 <Link to="/dashboard">
     <Button style={myStyle}>
        <p>Click Me!</p>
     </Button>
 </Link>

Solution 2:

LinkButton component - a solution for React Router v4

First, a note about many other answers to this question.

⚠️ Nesting <button> and <a> is not valid html. ⚠️

Any answer here which suggests nesting a html button in a React Router Link component (or vice-versa) will render in a web browser, but it is not semantic, accessible, or valid html:

<a stuff-here><button>label text</button></a>
<button><a stuff-here>label text</a></button>

☝Click to validate this markup with validator.w3.org ☝

This can lead to layout/styling issues as buttons are not typically placed inside links.


Using an html <button> tag with React Router <Link> component.

If you only want an html button tag…

<button>label text</button>

…then, here's the right way to get a button that works like React Router’s Link component…

Use React Router’s withRouter HOC to pass these props to your component:

  • history
  • location
  • match
  • staticContext

LinkButton component

Here’s a LinkButton component for you to copy/pasta:

// file: /components/LinkButton.jsx
import React from 'react'
import PropTypes from 'prop-types'
import { withRouter } from 'react-router'

const LinkButton = (props) => {
  const {
    history,
    location,
    match,
    staticContext,
    to,
    onClick,
    // ⬆ filtering out props that `button` doesn’t know what to do with.
    ...rest
  } = props
  return (
    <button
      {...rest} // `children` is just another prop!
      onClick={(event) => {
        onClick && onClick(event)
        history.push(to)
      }}
    />
  )
}

LinkButton.propTypes = {
  to: PropTypes.string.isRequired,
  children: PropTypes.node.isRequired
}

export default withRouter(LinkButton)

Then import the component:

import LinkButton from '/components/LinkButton'

Use the component:

<LinkButton to='/path/to/page'>Push My Buttons!</LinkButton>

If you need an onClick method:

<LinkButton
  to='/path/to/page'
  onClick={(event) => {
    console.log('custom event here!', event)
  }}
>Push My Buttons!</LinkButton>

Update: If you're looking for another fun option made available after the above was written, check out this useRouter hook.