logo

How href attribute of the anchor element got me stuck

Frontend developers are all familiar with the anchor element. I recently struggled with a bug which took me a while to figure out. The root cause is an unexpected use of href attribute.

href: Contains a URL or a URL fragment that the hyperlink points to. URLs are not restricted to Web (HTTP)-based documents, but can use any protocol supported by the browser.

Context

I was building a multi-level menus with the following requirements:

  • Only the leaf menu item is an active link
  • Clicking other non-leaf menu items should expand the next level items

What I did

It comes in handy for making each menu item with <a>. The only difference between leaf menu items and non-leaf menu items is that leaf menu items should have valid href which indicates the redirection destination. Therefore, I build a MenuItem component like this:

function MenuItem({ link, title, onClick = () => {} }) {
  return (
    <a href={link} onClick={onClick}>
      {title}
    </a>
  )
}

The Problem

Leaf menu items ✅

Leaf menu items work fine as the source { link: '/aaa', title: 'abc'} would be rendered as <a href='/aaa'> abc </a>

Non-leaf menu items ❌

For non-leaf menu items, the source { link: '', title: 'abc', onClick: console.log } would be rendered as <a href> abc </a>. Clicking such an anchor link will reload the page. This is a result of the fact that the current page is assumed to be the value of href attribute if the href attribute exists but no value is set for it. i.e.

<a href>aa</a>

is equivalent to

<a href={{location.href}}>aa</a>

Solutions

There are two possible solutions to work around this issue

  • Don't set href if link is exceptional

In this case, anchor element is used for semantic purpose only. The onClick handler will take care of the interaction.

function MenuItem({ link, title, onClick = () => {} }) {
  if (link) {
    return (
      <a href={link} onClick={onClick}>
        {title}
      </a>
    )
  }
  return <a onClick={onClick}>{title}</a>
}
  • Reset link to # if link is exceptional
function MenuItem({ link, title, onClick = () => {} }) {
  if (!link) {
    link = '#'
  }
  return (
    <a href={link} onClick={onClick}>
      {title}
    </a>
  )
}

Conclusion

To concludes, an anchor element with an empty href attribute will cause the page to reload when clicked. Having this knowledge in mind may save you time when you get into a similar track.