Linter · Rules
jsx-a11y/anchor-is-valid
Require links to have a real href, and buttons to be button elements
You can't reach an a without an href with the Tab key, and it isn't announced as a link. An a with href="#" or href="javascript:..." and an onClick is announced as a link but acts like a button. Space doesn't press it, and "open in new tab" leads nowhere.
Use a with a real address to go somewhere. Use button to do something.
- An
hrefis missing if it has no value, or isnullorundefined. - An
hrefis invalid if it's""or"#", or starts withjavascript:. - A link with spread props and no
hrefisn't reported, because thehrefmight be in the spread.
Configure
Off by default. To turn it on:
bunfig.toml
[lint.rules]
"jsx-a11y/anchor-is-valid" = "error" # or "warn"
Every option, set to its default. The ones that are commented out are unset by default.
bunfig.toml
[lint.rules]
"jsx-a11y/anchor-is-valid" = ["error", {
components = [], # list of strings
specialLink = [], # list of strings
# aspects = <list of strings>,
}]
Examples
Reported:
const home = <a>Home</a>;
const top = <a href="#">Back to top</a>;
const save = <a href="#" onClick={saveDraft}>Save</a>;
Not reported:
const home = <a href="/">Home</a>;
const top = <a href="#top">Back to top</a>;
const save = <button onClick={saveDraft}>Save</button>;
const tracked = <a href="/pricing" onClick={trackClick}>Pricing</a>;
const docs = <a {...linkProps}>Docs</a>;
Options
| Option | Default | What it does |
|---|---|---|
components | [] | Components to check like a. |
specialLink | [] | Other attributes that count as href. |
aspects | all three | Which checks run: "noHref" (no href), "invalidHref" (an href that goes nowhere), "preferButton" (an onClick with a missing or invalid href). |
const home = <Link>Home</Link>;
const home = <Link to="/">Home</Link>;
With only "invalidHref", a link without an href is allowed:
const home = <a>Home</a>;