15

The site I'm currently building is a little different from the norm. Instead of having multiple separate pages, all site content is on a single index.php file, and using absolute positioning and javascript the user "pans" across the site from page to page.

There are several different forms in the page as well. I was told not to worry about catering to people with Javascript disabled so we've opted for jQuery combined with JSON web-services for all forms on the page. This all works perfectly now, but there's a slight usability problem: tab-indices.

Since there are multiple forms, tabbing from one input-field to the next can result in the user suddenly jumping to an entirely different part of the site when the user reaches the end of a form and then tabs again. This is especially annoying in Firefox and Safari where buttons and radiobuttons are ignored when tabbing.

So here's my question: does anyone know of a way to constrain a user's focus to a single form element?

gillesv
  • 836
  • 2
  • 8
  • 19
  • Radios ignored by Firefox when tabbing? It does not seem to me... – neurino Mar 30 '11 at 09:37
  • Hmm, now I'm not seeing that either with Firefox 4 on Mac. But I've been told that 3.6 did. – gillesv Mar 30 '11 at 10:17
  • 2
    This can be a problem from an accessibility point of view: how would a keyboard user tab to the second form? Seems they'd get stuck in the first form and not be able to navigate beyond that. – BrendanMcK Mar 31 '11 at 00:22

4 Answers4

17
The site I'm currently building is a little different from the norm. Instead of having multiple separate pages, all site content is on a single index.php file, and using absolute positioning and javascript the user "pans" across the site from page to page.

Here's an alternate approach that might side-step this issue, and could end up being more accessible.

I'm assuming you have some elements on that page that you use to trigger the panning from one sub-page to the other?

If so, basic idea here is that when any page is "scrolled off", hide that 'sub-page' (presumably some container DIV) with display:none or visibility:hidden.

The key issue here is that content hidden with either of these two methods is non-tabbable, so the user can't accidentally tab into those hidden pages. Also importantly from an accessibility point of view, screenreaders know to ignore content that's marked up this way, so they will only read the current page (which is consistent with what a sighted user sees), not the entire page.

BrendanMcK
  • 14,252
  • 45
  • 54
  • This worked like a charm, and is a lot better accessibility-wise as now the tab-key only cycles between elements on screen and the browser's UI. Thanks! – gillesv Apr 01 '11 at 07:57
  • smart guy! plus one to you, sir. I've got a similar problem as the OP - and this is a great solution. – Bosworth99 Feb 17 '12 at 20:29
5

Why not increment your tabindex by, say, 100, per form?

So form 1 will have tabindeces running from 100-112, form 2 will have tabindex from 200-234, form 3 will have tabindex running from 300-314...

someguy
  • 51
  • 1
  • 1
1

Okay, I've decided to write my own solution that works in all major browsers (except Safari, but more on that later). Basically, how it'd work is that you assign a class to the last "tab-able" element in your form, which is usually the submit button, called 'lastInForm'. Simple HTML would look like this:

<form action="action.php">
<fieldset><input id="input1" name="input1" type="text" placeholder="text here" /></fieldset>
<fieldset><input id="input2" name="input2" type="text" placeholder="text here" /></fieldset>
<fieldset><input id="input3" name="input3" type="text" placeholder="text here" /></fieldset>

<button class="lastInForm" type="submit">I'm last</button>
</form>

Using the latest version of jQuery, I listen to the keydown event for that .lastInForm element and check for the keyCode 9, which corresponds to the tab-key. When I receive that event, I look up the closest form element, look up the first input element in said form, and apply focus to it.

Like so:

$(document).ready(function(evt){

$('.lastInForm').live('keydown', function(evt){
    if(evt.keyCode === 9){
        evt.preventDefault();

        var form = $(this).closest('form');
        var input = $('input:first', form);

        if(input !== undefined){
            input.focus();
        }
    }
});
});

... which results neatly in a form where you can loop through the elements using the tab key.

Now I mentioned earlier that it works on all major browser except Safari. The reason for this is that Safari by default doesn't allow you to tab to any element except textfields. To enable this behavior you have to go and check:

Preferences > Advanced > Universal Access: Press Tab to highlight each item on a webpage.

Why Apple has chosen to disable such a helpful accessibility feature by default is beyond me, but all I know is if a user enables this setting my script will work for them too.

gillesv
  • 836
  • 2
  • 8
  • 19
  • Now, I realize forcing this non-default behavior isn't exactly recommended for 99% of sites out there, but for this one edge case I'm working on it works like a charm. Hopefully someone will benefit from it. – gillesv Mar 30 '11 at 14:58
  • Possible downside to this: in most browsers (IE, Chrome, Firefox, Safari - Opera handles tabs differently...), when you tab to the end of a page, hitting tab again brings you to the browser UI - usually the address bar, then back into the page from there. This will interfere with that. (User can still hit some browser hot-key to go directly to the address bar, so they're not completely trapped, however.) Other things you may need to take into account: shift-tab moves in the opposite direction, so you need to handle the first field in a similar but complementary way. (more in next comment) – BrendanMcK Mar 31 '11 at 11:17
  • Also, if user does go direct to address bar (Ctrl-L in some Chrome/Firefox, F4 in IE) and tabs into doc from there (using either tab or shift-tab), there's no guarantee that the browser will return to the last-focused element; some browsers start back at the top. Are the other forms visible to the user when not in use? If they're not visible, then using display:none or visibility:false on those forms will hide them and take them out of the tab order completely, making all of these edge-cases moot. – BrendanMcK Mar 31 '11 at 11:24
  • Also I'm unsure if this will work on mobile devices, using the 'next/previous' buttons. – Adam Marshall Apr 03 '14 at 10:00
0

Use tabindex in your (X)HTML

This works flawlessly in Seamonkey 2.0.11 and Chrome 10.0

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>
    <title>untitled</title>
    <meta http-equiv="content-type" content="text/html;charset=utf-8" />
    <style type="text/css">
        /* absolute positioning */
        #form1 { position: absolute; bottom: 0; right: 0; width: 40%; }
        #form2 { position: absolute; top: 100px; left: 30px; width: 40%; }
       /* floats
        #form1 {float: right; width: 40%; }
        #form2 {float: left; width: 40%; } */
    </style>
</head>

<body>

<form id="form1" action="#" method="get">
<fieldset>
<legend>Form 1</legend>
<div><label for="t1">T1</label><input type="text" id="t1" name="t1" tabindex="1" /></div>
<div><label for="t3">T3</label><input type="text" id="t3" name="t3" tabindex="3" /></div>
<div><label for="t2">T2</label><input type="text" id="t2" name="t2" tabindex="2" /></div>
<input type="submit" tabindex="4" />
</fieldset>
</form>

<form id="form2" action="#" method="get">
<fieldset>
<legend>Form 2</legend>
<div><label for="t6">T6</label><input type="text" id="t6" name="t6" tabindex="6" /></div>
<div><label for="t5">T5</label><input type="text" id="t5" name="t5" tabindex="5" /></div>
<input type="submit" tabindex="7" />
</fieldset>
</form>

</body>

</html>
neurino
  • 11,500
  • 2
  • 40
  • 63
  • That doesn't work. Read my question: there are multiple forms on the same page. If I use the same tabindices in each form (i.e. first input gets tabindex 1, second input tabindex 2, etc...) the user keeps switching between each form which is even worse. If I use sequential tabindices the result remains the same as if I hadn't used tabindex at all. – gillesv Mar 30 '11 at 10:22
  • I read your question.. you should of course **not** repeat indexes and standard compilant browser _should_ follow indexes as w3c says. I'll try it on a test page. – neurino Mar 30 '11 at 10:26
  • @gillesv: added test page, also if this does not work in your page it could be due to errors in your (X)HTML – neurino Mar 30 '11 at 10:57
  • The result stays the same: I tab from T1 to T2 to T3 to T4 and then to T5. It shouldn't allow me to tab from T4 to T5 as T5 is in a different form. I'm sorry if this wasn't clear in my original question. I tried it on both Chrome 9 and Firefox 4. Thanks for the effort though. – gillesv Mar 30 '11 at 11:00
  • @gillesv: Why shouldn't it allow you? This breaks accessibility... how can a user reach T5 otherwise using Tab only? Lost time... – neurino Mar 30 '11 at 11:06
  • 2
    Because T5 is 2000 pixels on the other side of the page and accidentally tabbing to an unrelated form completely changes the context the user was in. I realize this site sounds like a accessibility nightmare, but it's for an advertising campaign and keyboard-only navigation is not a priority. I just need the tabindex to loop within the same form, and not jump to a different form. – gillesv Mar 30 '11 at 12:00