source: frontend/node_modules/eslint-plugin-jsx-a11y/docs/rules/anchor-is-valid.md

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 10.8 KB
Line 
1# jsx-a11y/anchor-is-valid
2
3💼 This rule is enabled in the following configs: ☑️ `recommended`, 🔒 `strict`.
4
5<!-- end auto-generated rule header -->
6
7The HTML `<a>` element, with a valid `href` attribute, is formally defined as representing a **hyperlink**. That is, a link between one HTML document and another, or between one location inside an HTML document and another location inside the same document.
8
9In fact, the interactive, underlined `<a>` element has become so synonymous with web navigation that this expectation has become entrenched inside browsers, assistive technologies such as screen readers and in how people generally expect the internet to behave. In short, anchors should navigate.
10
11The use of JavaScript frameworks and libraries, like _React_, has made it very easy to add or subtract functionality from the standard HTML elements. This has led to _anchors_ often being used in applications based on how they look and function instead of what they represent.
12
13Whilst it is possible, for example, to turn the `<a>` element into a fully functional `<button>` element with ARIA, the native user agent implementations of HTML elements are to be preferred over custom ARIA solutions.
14
15## How do I resolve this error?
16
17### Case: I want to perform an action and need a clickable UI element
18
19The native user agent implementations of the `<a>` and `<button>` elements not only differ in how they look and how they act when activated, but also in how the user is expected to interact with them. Both are perfectly clickable when using a mouse, but keyboard users expect `<a>` to activate on `enter` only and `<button>` to activate on _both_ `enter` and `space`.
20
21This is exacerbated by the expectation sighted users have of how _buttons_ and _anchors_ work based on their appearance. Therefore we find that using _anchors_ as _buttons_ can easily create confusion without a relatively complicated ARIA and CSS implementation that only serves to create an element HTML already offers and browsers already implement fully accessibly.
22
23We are aware that sometimes _anchors_ are used instead of _buttons_ to achieve a specific visual design. When using the `<button>` element this can still be achieved with styling but, due to the meaning many people attach to the standard underlined `<a>` due its appearance, please reconsider this in the design.
24
25Consider the following:
26
27```jsx
28<a href="javascript:void(0)" onClick={foo}>Perform action</a>
29<a href="#" onClick={foo}>Perform action</a>
30<a onClick={foo}>Perform action</a>
31```
32
33All these _anchor_ implementations indicate that the element is only used to execute JavaScript code. All the above should be replaced with:
34
35```jsx
36<button onClick={foo}>Perform action</button>
37```
38
39### Case: I want navigable links
40
41An `<a>` element without an `href` attribute no longer functions as a hyperlink. That means that it can no longer accept keyboard focus or be clicked on. The documentation for [no-noninteractive-tabindex](no-noninteractive-tabindex.md) explores this further. Preferably use another element (such as `div` or `span`) for display of text.
42
43To properly function as a hyperlink, the `href` attribute should be present and also contain a valid _URL_. _JavaScript_ strings, empty values or using only **#** are not considered valid `href` values.
44
45Valid `href` attributes values are:
46
47```jsx
48<a href="/some/valid/uri">Navigate to page</a>
49<a href="/some/valid/uri#top">Navigate to page and location</a>
50<a href="#top">Navigate to internal page location</a>
51```
52
53### Case: I need the HTML to be interactive, don't I need to use an a tag for that?
54
55An `<a>` tag is not inherently interactive. Without an href attribute, it really is no different from a `<span>`.
56
57Let's look at an example that is not accessible by all users:
58
59```jsx
60<a
61 className="thing"
62 onMouseEnter={() => this.setState({ showSomething: true })}
63>
64 {label}
65</a>
66```
67
68If you need to create an interface element that the user can click on, consider using a button:
69
70```jsx
71<button
72 className="thing"
73 onClick={() => this.setState({ showSomething: true })}
74>
75 {label}
76</button>
77```
78
79If you want to navigate while providing the user with extra functionality, for example in the `onMouseEnter` event, use an anchor with an `href` attribute containing a URL or path as its value.
80
81```jsx
82<a
83 href={someValidPath}
84 className="thing"
85 onMouseEnter={() => this.setState({ showSomething: true })}
86>
87 {label}
88</a>
89```
90
91If you need to create an interface element that the user can mouse over or mouse out of, consider using a div element. In this case, you may need to apply a role of presentation or an interactive role. Interactive ARIA roles include `button`, `link`, `checkbox`, `menuitem`, `menuitemcheckbox`, `menuitemradio`, `option`, `radio`, `searchbox`, `switch` and `textbox`.
92
93```jsx
94<div
95 role="menuitem"
96 className="thing"
97 onClick={() => this.setState({ showSomething: true })}
98 onMouseEnter={() => this.setState({ showSomething: true })}
99>
100 {label}
101</div>
102```
103
104In the example immediately above an `onClick` event handler was added to provide the same experience mouse users enjoy to keyboard-only and touch-screen users. Never fully rely on mouse events alone to expose functionality.
105
106### Case: I use Next.js and I'm getting this error inside of `<Link>`s
107
108This is a [known issue](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/issues/402) with Next.js's decision to construct internal links by nesting an href-free `<a>` tag inside of a `<Link>` component. Next.js is also [aware of the issue](https://github.com/vercel/next.js/issues/5533) and has an [RFC](https://github.com/vercel/next.js/discussions/8207) working towards a solution.
109
110Until the Next.js API can be updated to a more performant and standard setup, you have a few workaround options:
111
1121. If you have only a few `Link`s, or they're clustered in just a few files like `nav.tsx`, you can use disable macros like `{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}` to turn off validation of this rule for those usages.
113
1142. You can use the `Link` component's `passHref` prop to override a dummy `href` on the `<a>`:
115```typescript
116<Link href="/my-amazing-page" passHref>
117 <a href="replace">Go to my amazing page</a>
118</Link>
119```
120
1213. You can invest in a custom component that wraps the creation of the `Link` and `a`. You can then add your new custom component to the list of components to validate to ensure that your links are all created with a navigable href. A sample custom component is shared [here](https://gist.github.com/zackdotcomputer/d7af9901e7db87364aad7fbfadb5c99b) and it would be used like this:
122```typescript
123// Internally, LinkTo handles the making of the Link and A, collecting the
124// need for a lint workaround into a single file.
125// Externally, LinkTo can be linted using this rule, ensuring it will always
126// have a valid href prop.
127<LinkTo href="/my-amazing-page">Go to my amazing page</LinkTo>
128```
129
130### Case: I understand the previous cases but still need an element resembling a link that is purely clickable
131
132We recommend, without reserve, that elements resembling anchors should navigate. This will provide a superior user experience to a larger group of users out there.
133
134However, we understand that developers are not always in total control of the visual design of web applications. In cases where it is imperative to provide an element resembling an anchor that purely acts as a click target with no navigation as result, we would like to recommend a compromise.
135
136Again change the element to a `<button>`:
137
138```jsx
139<button
140 type="button"
141 className="link-button"
142 onClick={() => this.setState({ showSomething: true })}
143>
144 Press me, I look like a link
145</button>
146```
147
148Then use styling to change its appearance to that of a link:
149
150```css
151.link-button {
152 background-color: transparent;
153 border: none;
154 cursor: pointer;
155 text-decoration: underline;
156 display: inline;
157 margin: 0;
158 padding: 0;
159}
160```
161
162This button element can now also be used inline in text.
163
164Once again we stress that this is an inferior implementation and some users will encounter difficulty to use your website, however, it will allow a larger group of people to interact with your website than the alternative of ignoring the rule's warning.
165
166## Rule options
167
168This rule takes one optional object argument of type object:
169
170```json
171{
172 "rules": {
173 "jsx-a11y/anchor-is-valid": [
174 "error",
175 {
176 "components": ["Link"],
177 "specialLink": ["hrefLeft", "hrefRight"],
178 "aspects": ["noHref", "invalidHref", "preferButton"]
179 }
180 ]
181 }
182}
183```
184
185For the `components` option, these strings determine which JSX elements (**always including** `<a>`) should be checked for the props designated in the `specialLink` options (**always including** `href`). This is a good use case when you have a wrapper component that simply renders an `<a>` element (like in React):
186
187```js
188// Link.js
189const Link = props => <a {...props}>A link</a>;
190
191...
192
193// NavBar.js (for example)
194...
195return (
196 <nav>
197 <Link href="/home" />
198 </nav>
199);
200```
201
202For the `aspects` option, these strings determine which sub-rules are run. This allows omission of certain error types in restrictive environments.
203
204- `noHref`: Checks whether an anchor contains an `href` attribute.
205- `invalidHref`: Checks if a given `href` value is valid.
206- `preferButton`: Checks if anchors have been used as buttons.
207
208The option can be used on its own or with the `components` and `specialLink` options.
209
210If omitted, all sub-rule aspects will be run by default. This is the recommended configuration for all cases except where the rule becomes unusable due to well founded restrictions.
211
212The option must contain at least one `aspect`.
213
214### Succeed
215
216```jsx
217<a href="https://github.com" />
218<a href="#section" />
219<a href="foo" />
220<a href="/foo/bar" />
221<a href={someValidPath} />
222<a href="https://github.com" onClick={foo} />
223<a href="#section" onClick={foo} />
224<a href="foo" onClick={foo} />
225<a href="/foo/bar" onClick={foo} />
226<a href={someValidPath} onClick={foo} />
227```
228
229### Fail
230
231Anchors should be a button:
232
233```jsx
234<a onClick={foo} />
235<a href="#" onClick={foo} />
236<a href={"#"} onClick={foo} />
237<a href={`#`} onClick={foo} />
238<a href="javascript:void(0)" onClick={foo} />
239<a href={"javascript:void(0)"} onClick={foo} />
240<a href={`javascript:void(0)`} onClick={foo} />
241```
242
243Missing `href` attribute:
244
245```jsx
246<a />
247<a href={undefined} />
248<a href={null} />
249```
250
251Invalid `href` attribute:
252
253```jsx
254<a href="#" />
255<a href={"#"} />
256<a href={`#`} />
257<a href="javascript:void(0)" />
258<a href={"javascript:void(0)"} />
259<a href={`javascript:void(0)`} />
260```
261
262## Accessibility guidelines
263
264- [WCAG 2.1.1](https://www.w3.org/WAI/WCAG21/Understanding/keyboard)
265
266### Resources
267
268- [WebAIM - Introduction to Links and Hypertext](https://webaim.org/techniques/hypertext/)
269- [Links vs. Buttons in Modern Web Applications](https://marcysutton.com/links-vs-buttons-in-modern-web-applications/)
270- [Using ARIA - Notes on ARIA use in HTML](https://www.w3.org/TR/using-aria/#NOTES)
Note: See TracBrowser for help on using the repository browser.