How to work around jsx-a11y/no-static-element-interactions restriction? - reactjs

I used the following jsx to construct an entry in a FAQ table:
<li key={faqKey} className={styles.entry} onClick={handleExpandFn}>
<div>
<span className={`icon-next ${questionClassname}`} />
<span className={styles['question-text']}>{faqEntry.question}</span>
</div>
{faqEntry.answer}
</li>
The idea is that when a user click on the entry, it will toggle the open state of the entry. In the other word, when a user clicks on an open FAQ entry, it will close it. Otherwise it will open it.
However the li tag triggers this eslint violation: Visible, non-interactive elements should not have mouse or keyboard event listeners jsx-a11y/no-static-element-interactions
Unfortunately I don't think there is alternative way to the above html markup.
Since it is jsx, it also does not allow override such as // eslint-disable-line jsx-a11y/no-static-element-interactions (The inline comment will be printed out to the web page)
So how I can work around it? Happy to use different jsx markup or jsx eslint override

For those who are looking for a workaround, use role="presentation" in your tag.

Here's how you could revise the markup to be semantically appropriate and get the onclick off the <li>
<li key={faqKey} className={styles.entry}>
<h3>
<button type='button' onClick={handleExpandFn}>
<span className={`icon-next ${questionClassname}`} />
<span className={styles['question-text']}>{faqEntry.question}</span>
</button>
</h3>
<div className='add_a_panel_class_name_here'>
{faqEntry.answer}
</div>
</li>
So with the above:
the <h3> will make the titles of the FAQs easily searchable by screen reader users that are navigating by headings
placing the <button> inside of the <h3> gives you the appropriate element to attach a click event to (you want to use a button here because you're toggling state. an <a> should be used if you were going to a new page. You also don't need to add a tabindex to a button as they are inherently focusable).
There are some additional steps you'd likely want to implement, using ARIA expanded and controls attributes on the button, but the above should get you to a good base for moving beyond your error.

You could put eslint-disable-line in the jsx
<li // eslint-disable-line jsx-a11y/no-static-element-interactions
key={faqKey}
className={styles.entry}
onClick={handleExpandFn}
>
<div>
<span className={`icon-next ${questionClassname}`} />
<span className={styles['question-text']}>{faqEntry.question}</span>
</div>
{faqEntry.answer}
</li>
Another option, add role='presentation'
<li
key={faqKey}
className={styles.entry}
onClick={handleExpandFn}
role='presentation'
>
<div>
<span className={`icon-next ${questionClassname}`} />
<span className={styles['question-text']}>{faqEntry.question}</span>
</div>
{faqEntry.answer}
</li>

One solution I can remember is to use an anchor element with tab-index.
<a style={{display: 'list-item'}} tabIndex={-42} key={faqKey} className={styles.entry} onClick={handleExpandFn}>
<div>
<span className={`icon-next ${questionClassname}`} />
<span className={styles['question-text']}>{faqEntry.question}</span>
</div>
{faqEntry.answer}
</a>

if you are trying to implement menu using li then the right solution is using role="menuitem" in your li tags.
More details about it: https://w3c.github.io/aria/#menuitem

To overcome or avoid this error in ES Lint.
You can use three things based on your needs and requirements
aria-hidden="true" - will remove the entire element from the accessibility API
role= "presentation" - The presentation role is used to remove semantic meaning from an element and any of its related child elements.
role= "none" - will remove the semantic meaning of an element while still exposing it to assistive technology.
There are limitations as well:
Hide content from assistive technology
Cannot be used on a focusable
Element cannot be used on the parent of an interactive element

You can actually add the eslint override as a comment in JSX.
You have to nest the comment inside of braces {}, so that it will be interpreted as JavaScript. Then, of course, since it is a JavaScript comment, it will not be rendered in the JSX.
Depending on your style preference, you can either do it on the line directly before the code
{/* eslint-disable-next-line */}
<li key={faqKey} className={styles.entry} onClick={handleExpandFn}>
or, at the end of the same line
<li key={faqKey} className={styles.entry} onClick={handleExpandFn}> {/* eslint-disable-line */}
Check out the docs for more information on using JavaScript inside of JSX.

use
aria-hidden="true"
on non interactive element tag. like
<span aria-hidden="true" onClick={() => void}>Text</span>

Instead of rolling my implementation of faq table with collapse/expand interactive feature, I replace it with react-collapsible.
It of course gets rid of the jsx-a11y/no-static-element-interactions as a result.

Related

How to prevent </p> from ending line

<p>Dostępne: </p><p style={{color:'green'}}>{props.ile_aktywne}</p><p>Niedostępne: </p><p style={{color:'red'}}>{props.ile_nieaktywne}</p>
I want it to format as two lines
"Dostępne: 1"
"Niedostępne: 2"
Don't use a paragraph if you don't want to use it. That's what a <span> or <div> is for.
However, you can modify your HTML here:
<p>Dostępne: <span style="color:green">1</span></p>
<p>Niedostępne: <span style="color:red">1</span></p>
P tag will(If blocked behavior is not changed by CSS or Javascript) always creates a new line because it is a block tag. To get your output you can wrap it with a span tag as it is an inline tag.
<p>Dostępne: <span style={{color:'green'}}>{props.ile_aktywne}</span></p>
<p>Niedostępne: <span style={{color:'red'}}>{props.ile_nieaktywne}</span></p>
and if you want it as an ordered list add autonumbering. You can wrap with ol and replace p tag with li.
<ol>
<li>Dostępne: <span style={{color:'green'}}>{props.ile_aktywne}</span></li>
<li>Niedostępne: <span style={{color:'red'}}>{props.ile_nieaktywne}</span></li>
</ol>
Please check this as reference https://www.w3schools.com/html/html_blocks.asp

How to fix 'Static HTML elements with event handlers require a role.'?

My reactjs styledcomponent contains this code:
<a styling="link" onClick={() => this.gotoLink()}>
<SomeComponent />
</a>
This works fine but the eslint is complaining:
Static HTML elements with event handlers require a role.
How can I fix this error?
you need to add a role props in your a tag to avoid this warning, for example a button
<a role = "button" styling="link" onClick={() => this.gotoLink()}>
<SomeComponent />
</a>
I guess it is because the HREF props is missing in your anchor tag (not sure)
In my case, I used aria-hidden="true", then I was able to commit.
Before:
<i className="pwdicon" onClick={togglePasswordVisiblity} >
After I updated with aria-hidden:
<i className="pwdicon" onClick={togglePasswordVisiblity} aria-hidden="true" >
My problem was resolved.
Reference Link : https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/click-events-have-key-events.md
The earlier answers do give specific examples, what I was missing is a list of roles.
If someone is looking for other roles, a partial list is listed here.
An example of a missing role is tab which I needed.
Edit: per the comment request, my personal error was solved by adding role, but I was missing a list of allowed roles, see above for a partial list and a more complete (or possibly complete) list here, thanks to the comment by Caiof.
You need to set the role explicitly. So, try the next code:
<a role="button" styling="link" onClick={this.gotoLink}>
<SomeComponent />
</a>
Also, as you can see I've modified the onClick handler by replacing arrow function on regular declaration. It would reduce annoying and expensive calculations.
just add aria-hidden to it
<a aria-hidden styling="link" onClick={() => this.gotoLink()}>
<SomeComponent />
</a>
Just need to add the 'aria-hidden' attribute, like this:
<div onClick={handleClickCollectionCard} aria-hidden="true">

React site warning: The href attribute requires a valid address. Provide a valid, navigable address as the href value jsx-a11y/anchor-is-valid

I am getting a warning on a React site I built
./src/components/layout/Navbar.js [1] Line 31: The href attribute requires a valid
address. Provide a valid, navigable address as the href value jsx-a11y/anchor-is-valid
on the following code:
<p>
{isEmpty(profile.website) ? null : (
<a
className="text-white p-2"
href={profile.website}
target="#"
>
<i className="fas fa-globe fa-2x" />
</a>
)}
{isEmpty(profile.social && profile.social.twitter) ? null : (
<a
className="text-white p-2"
href={profile.social.twitter}
target="#"
>
<i className="fab fa-twitter fa-2x" />
</a>
)}
{isEmpty(profile.social && profile.social.facebook) ? null : (
<a
className="text-white p-2"
href={profile.social.facebook}
target="#"
>
<i className="fab fa-facebook fa-2x" />
</a>
)}
</p>
Even though the warning appears only for the first link, the same warning occurs on the next link if I remove the first link temporarily or change the href of the first link to a static URL.
The links need to appear as just an icon.
I have tried things such as using a button (did not have the correct look), using a function to open the dynamic url, and trying to force the href to be a string by using '' + {profile.website}. Many other suggestions have not worked.
Is there a way to prevent the error, without changing the jsx-a11y rules? Is what I have done not a good pattern, or is it just a bug in React or JSX?
Use href="/#" to replace href="#" OR href="javascript:;" OR href="javascript:void(0);"
It should remove the warnings.
These worked for me to get rid off the warning;
...
<a href={() => false}>...</a>
I've used href="!#" to remove warnings.
This is just a warning not a error that href attribute requires a valid value as # points to nowhere you can add links to href attributes to remove this warnings or if you are still in early development phase just write
/* eslint-disable jsx-a11y/anchor-is-valid */
On top of your code it will remove the warnings from the terminal, the above line disables the rule for the specified file where it is written
/* eslint-disable jsx-a11y/anchor-is-valid */
import React from 'react';
const Header = () =>{
return(
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<a className="navbar-brand" href="#">Navbar</a>
<button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
</nav>
)
}
To also prevent default I use this:
<a href="/#" onClick={(e) => e.preventDefault()}>Link Text</a>
Insert space after # so no more warning about it
replace href="#" to href="# "
but better if use like that href="#something" => href="#profile"
please use <button> instead of <a> when there's no href attribute.
official reference
If you really have to use the a tag, it maybe help you:
<a href="#" onClick={ev => {ev.preventDefault(); onClick();}}>"Hello A Tag"</a>
try replacing
target="#"
to
target="_blank"
I got the similar warning for href, I did as follows. May be try this. I got rid of the warning and functionality is intact. I am not sure this is correct. But tried this.
let hrefLink = '#'; passed as a arg like href={hrefLink}
If you are trying to render a page link dynamically then you can switch out an <a> tag for a <div> tag instead. The warning message will go away.
// DON't DO THiS
<a className="page-link" href="javascript:void(0);" onClick={() => onPageChange(page)}>
{page}
</a>;
// TRY THIS INSTEAD
<div className="page-link" onClick={() => onPageChange(page)}>
{page}
</div>;
If you put "javascript" word in the href attribute then you will get a RED WARNING:
index.js:1375 Warning: A future version of React will block
javascript: URLs as a security precaution. Use event handlers instead
if you can.
Reference: EsLint error resolution page
I've used the href in tag a. it's remove warnings.
<a href>Pictures</a>
You also can hide this warning adding a eslint-disable-next-line comment:
// eslint-disable-next-line
<a
onClick={e => {
// do something
}}
>
example
</a>
I've used the following to remove warnings.
<a href="/">
If we have written correct url but it also gives the same error like I put www.reactjs.org then it also gives the same warning. To resolve these problem we have an attribute in anchor tag i.e.
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
className used for style.
href used for links.
target used for open a link into new tab or not.
Rel is used to outcome from that warning in react.
I don't see something wrong if I'm refering to this.
https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-is-valid.md
Check in these links. Some people had the same problem than you and it comes from a Link component. They fix it in adding an exception to .eslintrc:
first link => https://github.com/evcohen/eslint-plugin-jsx-a11y/issues/340
and the second link => How can I fix jsx-a11y/anchor-is-valid when using the Link component in React?
Let me know if it's helping.
Late to the game but surprised no one recommended window.location, which simply sets the same exact route as the current?
Other solutions such as "#", "/#", and "/" actually modify the current route right? For a more generic solution just use window.location to stay on the current page without modification.
<a href="window.location" onClick={...}> Better Solution </a>
If you really want your anchor tag to have an onClick method you must use a valid href link orelse it will throw an error , The href attribute requires a valid value to be accessible. 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.
Change you button style with this property to make transparent
button{
background-color: Transparent;
background-repeat:no-repeat;
border: none;
cursor:pointer;
overflow: hidden;
outline:none;
}
and set the text inside the button to the resemble link color
I have use this color
.editcolor{
color: #1890ff;
}
I resolved my errors with this method.
I tried but most of the answers above did not work for me since the newer eslint does not allow most of them. Instead, it mentions disabling eslint for the specific line.
Simply add: // eslint-disable-next-line to the line which comes just before the jsx line that throws error.
Also, add this comment within {/* ... */} else it will show error.
Usage: {/* // eslint-disable-next-line */ }}
They advise the same thing:
Hope this solves it!
You just need to change "#" to "# ". Good luck
<li className="nav-item pointer">
<a onClick={logout} href="/#" className="nav-link">
LOGOUT
</a>
</li>
or just use
href="/"
Do Not Use: <a href='#'>Something</a> but instead use: <a href='/'>Something</a>

toggle extra detail for a record inside an ngRepeat

I'm working on a project where the client has supplied a pile of html where I need to plugin the data from our database and have hit a problem that I'm finding difficult to solve....
So first problem is with routing
<div ng-repeat="class in vm.classes">
<div class="class-overview">
<a href="#">
<span class="class-title">{{class.description}}</span>
... more stuff here
</a>
</div>
<div class="class-information collapse">
<div class="full-width">
{{class.longDescription}}
</div>
</div>
</div>
he has supplied some javascript to handle the click on class-overview
$('.class-overview a').on('click',function(e) {
e.preventDefault();
});
$('.class-overview').on('click',function() {
$('.class-overview.active').removeClass('active').next('.class-information').collapse('hide');
$(this).addClass('active').next('.class-information').collapse('show');//.css('top',offset).collapse('show');
});
and i have a line like this in my state provider
// default route
$urlrouterProvider.otherwise("/")
So the problem is that the ui-router handles the click and sends me back to the home page.
The ideal solution is to leave as much of his markup intact, so can anyone tell me how I stop ui-router handling the click?
or failing that, how I might use ng-click and ng-show to get the same effect, i.e. hiding and showing the class-information div...
If I understand well your question, you want to display the .class-information div when you click on the .class-overview element.
That can be done by using a variable in a ng-show like this:
<div ng-repeat="class in vm.classes">
<div class="class-overview">
<a href="#" ng-click="display = !display">
<span class="class-title">{{class.description}}</span>
... more stuff here
</a>
</div>
<div class="class-information" ng-show="display">
<div class="full-width">
{{class.longDescription}}
</div>
</div>
</div>
The display variable will be falsy when you land on the page, therefore the ng-click will be executed, this variable will be set to true.
I see that you are using a collapse class to hide the content if it is collapsed. Then you could use angular ng-class to put the collapse class when the display variable is false. Your div.class-information would look like this:
<div class="class-information" ng-class="{collapse: !display}">
<div class="full-width">
{{class.longDescription}}
</div>
</div>

Stagger (transition-delay) children to an element with ng-show

I'm creating a sitemap in a custom CMS powered by Angular.
I hide the lower levels of pages and toggle their visibility with a button. I add ng-animate to animate the "opening" of the lower levels of the sitemap.
This works fine for the <ul>, but I would rather have its child <li> enter with a longer transition-delay for every item for a nice waterfall effect and this is where I get stuck.
At first I figured simply adding a transition-delay to the <li> would be sufficient, but for whatever reason I'm even unable to add a regular transition to the <li>. I read about the -stagger class, but it never gets applied.
Markup:
<ul>
<li ng-repeat="page in data"
ng-class="{'children-visible': isVisible}"
ng-init="isVisible = false">
{{page.pagename}}
<button ng-if="page.sub"
ng-click="$parent.isVisible = !isVisible">
</button>
<ul ng-if="page.sub"
ng-show="isVisible"
ng-animate="'animate'">
<li ng-repeat="page in page.sub">
{{page.pagename}}
</li>
</ul>
</li>
</ul>
Here's a picture of the markup if it helps you, er, picture it:
If relevant, I use version 1.2.16 of both angular.js and angular-animate.js.
So, in short: How do I add a stagger/transition delay to children of an element with ng-show?

Resources