Opened 8 years ago

Last modified 5 years ago

#6006 reopened enhancement

Dialog: Consider changing focus implementation to avoid scrolling content

Reported by: jakerella Owned by:
Priority: minor Milestone: none
Component: ui.dialog Version: 1.8.4
Keywords: tabbable jump dialog scroll Cc:
Blocked by: Blocking:

Description

I posted this issue in the forums (http://forum.jquery.com/topic/opening-dialog-with-link-in-content-causes-flicker-jumping), but have re-posted here as I implemented a solution of my own.

A dialog with no links or form elements in the dialog content opens as expected with focus given to the dialog itself; however, a dialog which has any "tabbable" element in its content causes the dialog content to jump down to the first of those elements. From the comments in the code it looks like this was intended for form elements and dialogs where all content is immediately visible; however if you have content that scrolls vertically with a link in the text the dialog content "jumps" to the first link (or other tabbable element).

My fix is simply to add an option called "autoFocus" which defaults to "true" (resulting in no change of behavior). Setting the option to "false" causes the "open" method to always focus on the dialog as a whole and not the first tabbable element.

I have attached my revised version of the dialog widget code. There are only 3 additional lines of code (and a couple close brackets).

Attachments (1)

jquery.ui.dialog.js.txt (20.3 KB) - added by jakerella 8 years ago.

Download all attachments as: .zip

Change History (15)

Changed 8 years ago by jakerella

Attachment: jquery.ui.dialog.js.txt added

comment:1 Changed 8 years ago by Scott González

Resolution: duplicate
Status: newclosed

Duplicate of #4731.

comment:2 Changed 6 years ago by Scott González

Milestone: TBD

Milestone TBD deleted

comment:3 Changed 6 years ago by deAtog

The fix for #4731 does not address this issue and this is not strictly a duplicate of that issue. The fix for #4731 allows one to add the 'autofocus' attribute to the element which should receive the focus when the dialog is opened followed by :tabbable content, the button pane, and then the close button.

Setting the tabindex of links to a negative number removes them from the list of :tabbable content. If this were applied to the links at the bottom of the dialog mentioned in this bug report the dialog would not autofucus the first link upon opening. While this addresses the issue mentioned it prevents the user from tabbing to these links, an undesired side effect.

dialog('open') should instead focus the first tabbable content element by tabindex if and only if that element is contained within the current view port of the dialog content area. IE: element top + element height <= dialog content height. If tabbable content exists, but the first tabbable element would cause the content window to scroll, the dialog should be focused instead.

The autofucus attribute should be removed, using tabindex should be the preferred method of selecting which elements receive focus via tab and in which order.

comment:4 Changed 6 years ago by Scott González

Milestone: none

This behavior is not changing. There are multiple specs (specifically HTML and ARIA) which prescribe behavior. As far as I know, visibility is never a consideration for whether an element gains initial focus.

comment:5 in reply to:  4 Changed 6 years ago by deAtog

Replying to scott.gonzalez:

This behavior is not changing. There are multiple specs (specifically HTML and ARIA) which prescribe behavior. As far as I know, visibility is never a consideration for whether an element gains initial focus.

I disagree. I can't name a single browser that automatically scrolls to and focuses a link at the bottom of several pages of content simply because it was the first tabbable/focusable element within the content. You should review section 7.4. When the dialog is opened it essentially replaces the content of the active document. Maybe the correct fix for all of this is to simply remove auto-focusing and use tabindex appropriately. The spec states browsers should focus content according to the tab order. The only reason focus is being called during dialog.open() is to prevent the close button from initially gaining focus. If the close button were given a high enough tabindex, the browser's own focusing mechanism could choose the appropriate element to focus.

comment:6 Changed 6 years ago by Scott González

I can't name a single browser that automatically scrolls to and focuses a link at the bottom of several pages of content simply because it was the first tabbable/focusable element within the content.

That's not the case we're talking about. Open this in any browser that supports autofocus: http://jsbin.com/apolis/1

You should review section 7.4.

You should review the dialog element: http://www.w3.org/html/wg/drafts/html/master/interactive-elements.html#the-dialog-element

When the dialog is opened it essentially replaces the content of the active document. Maybe the correct fix for all of this is to simply remove auto-focusing and use tabindex appropriately. The spec states browsers should focus content according to the tab order.

The spec never mentions tabindex in relation to dialogs. Dialogs are something new and have different behavior than initial page load.

The only reason focus is being called during dialog.open() is to prevent the close button from initially gaining focus.

That's not at all true. Opening a dialog is literally just showing a div. That has no change on the focus, which means some users are completely lost and have no context for what is going on. THAT is the reason that focus is called.

If the close button were given a high enough tabindex, the browser's own focusing mechanism could choose the appropriate element to focus.

Why do you think this would happen?

comment:7 in reply to:  6 Changed 6 years ago by deAtog

I can't name a single browser that automatically scrolls to and focuses a link at the bottom of several pages of content simply because it was the first tabbable/focusable element within the content.

That's not the case we're talking about. Open this in any browser that supports autofocus: http://jsbin.com/apolis/1

This issue is not about the autofocus attribute. This issue is about dialogs containing content like this:

http://jsbin.com/apolis/2

Open that in any browser and you'll see that it does not focus the link at the bottom automatically. It displays the first page of text as expected and the user can still tab to the link at the bottom.

You should review section 7.4.

You should review the dialog element: http://www.w3.org/html/wg/drafts/html/master/interactive-elements.html#the-dialog-element

When the dialog is opened it essentially replaces the content of the active document. Maybe the correct fix for all of this is to simply remove auto-focusing and use tabindex appropriately. The spec states browsers should focus content according to the tab order.

The spec never mentions tabindex in relation to dialogs. Dialogs are something new and have different behavior than initial page load.

Okay, some clarification is actually needed here. There is some documentation, but it it only applies to modal dialogs. To this regard the spec says when the showModal() method of a dialog is invoked, the user agent must run the following steps:

...

  1. Let dialog's Document be blocked by the modal dialog dialog.
  2. Push dialog onto dialog's Document's pending dialog stack.
  3. Let control be the first element in tree order whose nearest ancestor dialog element is dialog and that has an autofocus attribute specified, if any.
  4. If there is no control, then abort these steps.
  5. Run the focusing steps for control.

There is no behavior defined for a modal dialog that does not contain an element with the autofocus attribute (step 9 says to abort). The presumed behavior is that the dialog itself should receive the focus, not the first tabbable element. The spec need not specifically add information about tabindex in regards to modal dialogs as all elements outside the dialog are rendered inert (step 6) and the rules governing sequential focusing and tabindex remain in effect. Additionally, no functionality is defined for non-modal dialogs containing an element with an autofocus attribute (different section).

The only reason focus is being called during dialog.open() is to prevent the close button from initially gaining focus.

That's not at all true. Opening a dialog is literally just showing a div. That has no change on the focus, which means some users are completely lost and have no context for what is going on. THAT is the reason that focus is called.

If the close button were given a high enough tabindex, the browser's own focusing mechanism could choose the appropriate element to focus.

Why do you think this would happen?

For a modal dialog without the autofocus attribute applied to any elements, the dialog itself would be focused similar to how the document initially has focus when a page is loaded (All other page elements outside the dialog are inert according to step 6). If it's not a modal dialog, there's no indication that the focus should be changed regardless of it containing an element having the autofocus attribute specified or not.

comment:8 Changed 6 years ago by Scott González

Yes, but the HTML spec ignores accessibility concerns. You need to also read about ARIA roles: http://www.w3.org/TR/wai-aria-practices/#modal_dialog

Specifically:

When the dialog box is opened, focus should be set to the first tab focusable element within the dialog. If there is no tab focusable element within the dialog box contents, set the focus to the item that is used to cancel or close the dialog. There must be some element within the dialog which can accept focus in order for the screen reader to speak the dialog title and information when it is opened.

Please ignore the fact that there are differences for modal and non-modal dialogs. There is no such thing as a non-modal dialog in ARIA. This is the broken world that we live in.

Arguing about the semantics of a normal page and how that related to a dialog that has just been opened is not going to move this discussion forward at all.

comment:9 Changed 6 years ago by deAtog

I'm not sure we're going to reach a consensus on this. ARIA says one thing while the HTML specification states another. The HTML spec clearly states, the only element which should receive the focus is the one with the autofocus attribute. On the other hand ARIA states the first tab focusable element should receive the focus. Considering the deficiencies in ARIA in this regard, and the typical functionality expressed by browsers, I'm more favorable of the HTML specification. In the end some sort of compromise may inevitably be needed. Strictly adhering to ARIA by focusing a link at the end of a bunch of text will cause the content to scroll which is unusable for the vast majority of sighted individuals such as myself who read things from top to bottom. Additionally, it would not make sense to render such a link as untabbable so as to further hinder the usability of ARIA based screen readers.

The only sensible compromises are:

  1. Focus the first tab focusable element if and only if it does not cause the view port to scroll or the element with the autofocus attribute specified. Otherwise the focus the cancel or close button.
  1. If the dialog contains an element with autofocus specified, focus it. Otherwise focus the cancel or close button.

The first does it's best to adhere to both specifications as much as possible. The second essentially replaces "first tab focusable element" with "autofocused element" within the ARIA specification. Of the two, the first preserves much of the functionality currently present. With the second, autofocus would need to be specified in order to focus anything other than the cancel or close button.

Of the two, the second is probably the cleanest of the two as its behavior is very well defined and easy to explain and document. I would much rather see this be the preferred implementation over the alternative.

comment:10 Changed 6 years ago by jakerella

FWIW, I agree that it will be difficult to find a consensus, but I would go with option (2) above as well. Perhaps the ARIA spec is expecting that there would be navigation in the dialog, thus focusing on the first tabbable element makes sense? Honestly though, I don't think we can reconcile these two specs (at least, not in this fourm).

In any case, thanks to both of you for at least discussing the issue.

comment:11 Changed 6 years ago by Scott González

Resolution: duplicate
Status: closedreopened
Summary: Opening Dialog with link in content causes jumpingDialog: Consider changing focus implementation to avoid scrolling content

comment:12 Changed 5 years ago by Jörn Zaefferer

Elsewhere (http://bugs.jqueryui.com/ticket/9101#comment:7) TJ suggests to override _focusTabbable to control how focus is set inside the dialog. Maybe we can just document that method as an Extension Point to address this issue.

comment:13 Changed 5 years ago by Scott González

No. We shouldn't document _focusTabbable(). We should find a good solution.

comment:14 Changed 5 years ago by Jörn Zaefferer

I've reviewed the discussion here again. Looking at the sample posted by Scott (http://jsbin.com/apolis/1 ) in both Firefox and Chrome suggest that we should keep our focus logic as is, but prevent the scrolling to happen. When I open that sample, the page doesn't scroll, even though the input receives input.

If that's the way to go, we would probably have to modify _focusTabbable() to:

  • store the scrollTop of the dialog before doing anything else
  • find an element and focus on it
  • restore the scrollTop of the dialog to the value it had previously

That's seems reasonable to cover in a unit test as well, apart from the difficulties to test scroll in IE (https://github.com/jquery/jquery-ui/commit/e263ebda99f3d414bae91a4a47e74a37ff93ba9c#commitcomment-4234183).

Note: See TracTickets for help on using tickets.