React: The href attribute requires a valid value to be accessible

The React warning “The href attribute requires a valid value to be accessible” means you didn’t put a valid URL path in an href attribute for an <a> tag. To fix this, make sure your href attribute starts with a forward slash (/). If you’re trying to simulate a link but don’t actually want it to go anywhere, you should use a <button> styled as a link instead.

I discovered this warning while working on the SuperTokens example. I was trying to create a fake link in the menu to log the user out. In the React SuperTokens SDK, logging out is done via a function call. That’s not an issue, however, a button in the menu when everything else was a link didn’t look quite right.

Let’s take a look at my first attempt to achieve a “fake” link and what went wrong.

Problem: your anchor tag needs an href, but you don’t want it to do anything

The below code comes from the SuperTokens example project I wrote about previously. If you want to learn more about how to secure your app with SuperTokens, I’d check out the article. But right now we’re only talking about the React warning you get when your href attribute isn’t correct.

The code that triggered the warning is below:

import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react";
import { signOut } from "supertokens-auth-react/recipe/emailpassword";
import { SessionAuth, useSessionContext } from 'supertokens-auth-react/recipe/session';
import {
    Routes,
    Route,
    Link,
    useNavigate,
} from "react-router-dom";
import * as reactRouterDom from "react-router-dom";

import HomePage from "./HomePage";

export default function Main() {
    const {loading, doesSessionExist} = useSessionContext();
    const navigate = useNavigate();
    const onSignOut = async () => {
        await signOut();
        navigate("/auth");
    }

    return (
        <div id="main">
            <div id="menu">
                <ul>
                    <li><Link to="/">Home</Link></li>
                    <li>
                        { !loading &&
                            doesSessionExist
                                ? <a href="#" onClick={onSignOut}>Sign Out</a>
                                : <Link to="/auth">Sign In</Link>
                        }
                    </li>
                </ul>
            </div>
            <Routes>
                <Route path="/" element={
                    <SessionAuth>
                        <HomePage />
                    </SessionAuth>
                } />
                {getSuperTokensRoutesForReactRouterDom(reactRouterDom)}
            </Routes>
        </div>
    );
}
JavaScript

All we’re doing here is creating a rudimentary menu system for our example app and defining some routes with react-router-dom to display our pages to the user. Our /auth route was easy, it can just be a <Link> element with the to prop pointing right to that path.

However, our “Sign Out” link (which should really be a button) defines the onClick prop which calls our onSignOut function. A little weird for an <a> tag, but not unheard of. I assumed putting a # in the href prop would suffice:

                    <li>
                        { !loading &&
                            doesSessionExist
                                ? <a href="#" onClick={onSignOut}>Sign Out</a>
                                : <Link to="/auth">Sign In</Link>
                        }
JavaScript

But then got this error when WebPack compiled the app:

Line 30:35:  The href attribute requires a valid value to be accessible. Provide a valid, navigable address as the href value. If you cannot provide a valid href, but still need the element to resemble a link, use a button and change it with appropriate styles. Learn more: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/anchor-is-valid.md  jsx-a11y/anchor-is-valid

This is just a warning, but we don’t want warnings in our app, especially if it’s going to show up every time we rebuild it. Luckily, the solution was very simple.

Solution 1: use /# instead of just #

The easiest way to fix this error is to just put a slash in front of the pound sign like this:

                    <li>
                        { !loading &&
                            doesSessionExist
                                ? <a href="/#" onClick={onSignOut}>Sign Out</a>
                                : <Link to="/auth">Sign In</Link>
                        }
JavaScript

But, if you recall the error message, “best practice” would be to use a button instead and just style it as a link. The reason for this is, depending on the type of front-end router you’re using, this might trigger a page refresh. In our example, the onSignOut function just forces the browser to load another page anyway, so it might not be noticeable. But then again, it might actually break your app, and not all of your users’ browsers are guaranteed to behave the same way with this method.

So let’s look at how to use a button instead next.

Solution 2: use a button instead

Here’s how you’d replace the “do nothing” link with a button:

                    <li>
                        { !loading &&
                            doesSessionExist
                                ? <button onClick={onSignOut}>Sign Out</button>
                                : <Link to="/auth">Sign In</Link>
                        }
JavaScript

That’s all there is to it. Of course, you’ll probably want to style the button to look like a link.

Conclusion

In React, your <a> tags should have a valid URL path in the href prop. If you don’t have one, you’ll get the warning “The href attribute requires a valid value to be accessible”. This won’t break your app, but you’ll have to see the warning every time you rebuild it. The best way to fix this is to make the link a button instead (assuming you got this error because you were trying to simulate a link rather than actually navigate somewhere) and then use CSS to style it like a link. That’s kind of a pain, especially for a quick and dirty example. So, if you’d rather skip the hassle, you can just set the href prop to /#.

But I’d definitely recommend using a button instead.