Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

accessability javascript: make down up arrow keys simulate TAB key [closed]

Thanks for your attention, I appreciate any feedback.

My current script half works (click "i" in bottom right corner".

It will focus first link AFTER pressing TAB (or keyCode 9) to focus links inside <div id="Foo2">. But I have to hit TAB first.

  1. How make script autofocus 1st link WITHOUT having to press TAB?
  2. Can script reverse too? Up arrow should "re-autofocus" input field and let the user continue typing...
  3. How do we make ESC close collapse? So the user's don't have to reclick the button.
<script type="text/javascript">
$(document).keydown(
  function(e)
  {    
      if (e.keyCode == 38) {      
          e.preventDefault(); // this makes it so arrow up doesn't scroll
          $("link:focus").prev().focus();

      }
      if (e.keyCode == 40) {
          e.preventDefault();
          $("link:focus").next().focus();

      }
  }
);
</script>

standard bootstrap 3 collapse with input search and hidden well:

<a class="demo" data-toggle="collapse" href="#Foo"><i class="fa fa-info"></i></a>
<div class="collapse" id="Foo">
    <form action="" method="post" role="form">
       <input autocomplete="off" autofocus="" class="form-control" id="inputSearch" name="search" placeholder="" type="text">
    </form>
    <!-- this auto populates on search input with database stuff -->
    <div class="hidden" id="Foo2"></div> 
</div>

here is hidden well / autopopulate stuff after user search query:

<div id="Foo2" class="">
    <div tabindex="-1">
        <a class="link" href="#">database result #1</a>
        <a class="link" href="#">database result #2</a>
        <a class="link" href="#">database result #3</a>
        <a class="link" href="#">database result #4</a>
    </div>
</div>
like image 226
Matt G. Avatar asked Feb 21 '20 22:02

Matt G.


People also ask

How do you code arrow keys in JavaScript?

To detect the arrow key when it is pressed, use onkeydown in JavaScript. The button has key code. As you know the left arrow key has the code 37. The up arrow key has the code 38 and right has the 39 and down has 40.

How do I make a div tab accessible?

By adding key handling, a tab index, a role and an aria-label, this div essentially becomes an accessible button and then we can add whatever content we want within the button. This solution works great for simple components that actually look and function like a button.

What is key for Tab in JavaScript?

JavaScript tab key code is 9. Use the keydown event to get the tab key code or char code in JavaScript.


2 Answers

As this is marked accessibility there are a lot of things to consider that will not only make your life easier but make things more accessible.

This answer got quite long so section 4 covers most of your points, everything else are improvements you can make for accessibility.

1. HTML Semantics

1a - Use buttons for buttons, anchors for anchors

As your "i" button does not work without JavaScript you should use a <button> instead of an anchor (<a>).

1b - Make sure your screen reader users can access information

Also you need some 'visually-hidden' text within the <button> as screen readers will not have any information to present to users (icons are not accessible).

1c - Make sure icons are visible to all users.

Finally using font-awesome is a bad idea both from performance and from an accessibility perspective. Some users (i.e. those with dyslexia) may use a custom style sheet to swap out the fonts on your site. Some of these style sheets swap all of the fonts out, this includes your icon fonts (so your pretty icons then become the dreaded 'rectangle' for missing fonts).

Improve your site load times with only 500 BYTES per inline SVG vs 185 KILOBYTES for the two font awesome fonts and reduce your request count by 2.

Rough Example for number 1

.visually-hidden { 
    position: absolute !important;
    height: 1px; 
    width: 1px;
    overflow: hidden;
    clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
    clip: rect(1px, 1px, 1px, 1px);
    white-space: nowrap; /* added line */
}
svg{
   width: 40px;
   height: 40px;
   padding: 4px;
}
<!-- Button not an anchor -->
<button class="demo" data-toggle="collapse">
     <!--I added an inline SVG instead here-->
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
			<path style="fill:#030104;" d="M10,16c1.105,0,2,0.895,2,2v8c0,1.105-0.895,2-2,2H8v4h16v-4h-1.992c-1.102,0-2-0.895-2-2L20,12H8 v4H10z"/>
			<circle style="fill:#030104;" cx="16" cy="4" r="4"/>
</svg>
     <!--This 'Visually Hidden' text is accessible to screen readers but isn't visible, see the CSS for a reusable Class you can use to hide things visually but still have them accessible-->
    <span class="visually-hidden">Information / Relevant Text Explaining The Button</span>
</button>

1d - Inputs need accessible labels

At the moment when a screen reader user lands on your search <input> they will not know what the field is called.

Use a visually hidden <label> that is associated with the <input> using for="" as the easiest way to fix this. The for="" should point to the ID of the relevant input.

<label for="inputSearch" class="visually-hidden">Search Criteria</label>
<input autocomplete="off" autofocus="" class="form-control" id="inputSearch" name="search" placeholder="" type="text">`

1e - lists should be lists

Your results should be returned within an unordered list <ul>.

For screen reader users this then let's them know how many results have been returned (as a screen reader will say 'list, 4 items, first item selected' or something similar.)

So wrap your search results in an <ul> and <li>. As an added bonus you can then use the <ul> as the container to remove unnecessary nodes.

<ul id="Foo2" class="" tabindex="-1">
        <li><a class="link" href="#">database result #1</a></li>
        <li><a class="link" href="#">database result #2</a></li>
        <li><a class="link" href="#">database result #3</a></li>
        <li><a class="link" href="#">database result #4</a></li>
</ul>

2. Colour Contrast

Although not shown in your code on the link to your website the links in your collapsable section are #646970 for the font and #DEDEDEfor the background.

As the font is only 17px this means that you do not pass WCAG AA for colour contrast here.

Either change the font size to at least 18.66px (19px) or make the background grey lighter (#E8E8E8 would work as a minimum - although i would probably go for #3D3F43 foreground and #D4D4D4 background to get a WCAG AAA rating for contrast of over 7:1).

3. WAI-ARIA

WAI-ARIA is used to tell screen readers additional information that isn't available using just <html> elements.

3a - aria-expanded

Your 'i' button is a toggle for collapsible information so you need to add aria-expanded="false" to the button initially and then change this to aria-expanded="true" when you open the collapsed section.

You can do this within your <button> click to open and or close the hidden section (toggling the state).

Doing this informs the screen reader that clicking this <button> will open up some information and will also let them know the state (is it opened aria-expanded="true" or is it closed aria-expanded="false").

3b - aria-owns and other aria

This answer is getting quite long and scary so instead I will provide a link that demonstrates an accessible autocomplete that you can explore.

4. Managing Focus

4a - focusing first input

To focus the first link you just need to fix your selector (you didn't show this in your example).

$("#Foo a:first").focus(); is all you need here.

4b - other focus management

You should treat the section that appears as a modal and trap the focus inside (so constant tabbing will loop within all the available controls).

With regards to tabbing and alt tabbing please see this answer I gave - This helper lets you find all the focusable items within a container and then ensure that focus stays within that container. It isn't perfect (as it only intercepts Tab and Alt + Tab and screen reader users may use other keys but it is a great start.)

Finally to close the item the Escape Key is accessible with e.keyCode == 27, I am sure you can work that one out yourself, don't forget to toggle to aria-expanded="false" after pressing it (also focus the 'i' button when you press Escape as it is expected behaviour to be returned back to where you were on Escape to Close.)!

I am sure I have missed some accessibility issues but that should give you a real good start (and implementing the items listed will give you a good understanding of the basics of accessibility for future development!)

Any questions just ask.

like image 96
Graham Ritchie Avatar answered Sep 25 '22 00:09

Graham Ritchie


Let's go by parts:

How make script autofocus 1st link WITHOUT having to press TAB?

You can use Bootstrap's collapse event shown.bs.collapse:

$('#Foo').on('shown.bs.collapse', function () {
    $('#Foo2').children().children('a:first').focus(); //it will focus the first "a" tag in "div tabindex=-1"
    e.preventDefault(); //If you call HTMLElement.focus() from a mousedown event handler, you must call event.preventDefault() to keep the focus from leaving the HTMLElement (seen on https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/focus)
});

Can script reverse too? Up arrow should "re-autofocus" input field and let user continue typing...

Yup; modifying your code, it would look like this:

if (e.keyCode == 38) {
        e.preventDefault();
        $("#inputSearch").focus();
      }

How do we make ESC close collapse? So user's don't have to reclick button

Yes, using collapse('hide'):

if (e.keyCode == 27) {
        e.preventDefault();
        $("#Foo").collapse('hide');
}

Notes:

  • Use keyup instead of keydown.
  • A dot is missing in $(link:focus).

Final JQuery code looks like this:

$(document).keyup(
    function(e) {
      if (e.keyCode == 38) {
        e.preventDefault(); // this makes it so arrow up doesn't scroll
        $("#inputSearch").focus();

      }
      if (e.keyCode == 40) {
        e.preventDefault();
        $(".link:focus").next().focus();

      }
      if (e.keyCode == 27) {
        e.preventDefault();
        $("#Foo").collapse('hide');

      }
    }
  );

$('#Foo').on('shown.bs.collapse', function () {
  $('#Foo2').children().children('a:first').focus();
  e.preventDefault();
});
like image 45
padaleiana Avatar answered Sep 26 '22 00:09

padaleiana