diff --git a/source b/source index 2c5ffa547d9..af0338245fc 100644 --- a/source +++ b/source @@ -4373,7 +4373,18 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute

In addition, the following aria-* content @@ -12625,6 +12636,7 @@ interface HTMLUnknownElement : HTMLElement { [CEReactions, Reflect] attribute boolean autofocus; [CEReactions, ReflectSetter] attribute long tabIndex; + [CEReactions, Reflect] attribute DOMString focusgroup; undefined focus(optional FocusOptions options = {}); undefined blur(); }; @@ -13896,6 +13908,7 @@ https://software.hixie.ch/utilities/js/live-dom-viewer/?%3C%21DOCTYPE%20HTML%3E%

  • dir
  • draggable
  • enterkeyhint
  • +
  • focusgroup
  • headingoffset
  • headingreset
  • hidden
  • @@ -85975,6 +85988,313 @@ dictionary CommandEventInit : EventInit {
    <div contenteditable autofocus>Edit <strong>me!</strong><div>
    +

    The focusgroup attribute

    + +

    The focusgroup + content attribute provides declarative focus navigation for a group of related focusable + elements. When applied to an element, it enables Directional Navigation among its + focusable descendants, forming a focus group. Directional Navigation is navigation by spatial direction (such as up, down, left, or right), as determined by the user agent and input device (for example, arrow keys, gamepad, remote control, etc.). In contrast, Sequential focus navigation refers to navigation in the order defined by the sequential focus navigation order (see definition), often via Tab and Shift+Tab.

    + +
    Concepts
    + +

    The attribute's value is a string of space-separated tokens. The first token must either be a + behavior token, which defines the primary interaction pattern, or the special token + none which is used alone to opt out of focusgroup behavior. If a behavior token is + specified, modifier tokens can be provided subsequently.

    + +

    Behavior tokens define the interaction pattern, which refers to how the directional navigation inputs are used to move focus between focusgroup items.

    + +

    The following interaction patterns are defined:

    + + + + + + + + + + + + + + + + + + +
    Token + Type + Interaction + Description +
    toolbar + Behavior + Linear + Indicates a toolbar pattern. Infers a toolbar role. +
    tablist + Behavior + Linear + Indicates a tablist pattern. Infers a tablist role for the owner and a tab role for items. +
    radiogroup + Behavior + Linear + Indicates a radiogroup pattern. Infers a radiogroup role for the owner and a radio role for items. +
    listbox + Behavior + Linear + Indicates a listbox pattern. Infers a listbox role for the owner and an option role for items. +
    menu + Behavior + Linear + Indicates a menu pattern. Infers a menu role for the owner and a menuitem role for items. +
    menubar + Behavior + Linear + Indicates a menubar pattern. Infers a menubar role for the owner and a menuitem role for items. +
    wrap + Modifier + + Enables navigation to wrap from the last item to the first, and vice-versa. +
    inline + Modifier + + Restricts arrow key navigation to the inline axis (e.g., left/right arrows). +
    block + Modifier + + Restricts arrow key navigation to the block axis (e.g., up/down arrows). +
    no-memory + Modifier + + Disables the "last focused item" memory when re-entering the focus group. +
    none + Special + + Opts the element and its descendants out of any ancestor focus group. Must be used alone. +
    + +

    A focusgroup owner is an element with a valid focusgroup attribute specified, where the attribute value contains a behavior token (not none).

    +

    The focusgroup scope of a focusgroup owner is all of its shadow-including descendants, excluding any descendants that are a focusgroup owner themselves or are are in a different focusgroup scope or have opted out with focusgroup="none".

    +

    A focusgroup item is any focusable element within the focusgroup scope.

    +
    ARIA Role Inference
    + +

    When a behavior token is used, the user agent may infer a corresponding ARIA role for the focusgroup owner and its items. This inference must only occur if the element would otherwise have a generic role (such as a div or span) and does not have an explicit role attribute.

    + +

    For example, <div focusgroup="toolbar"> would be exposed with a toolbar role. However, if the element has existing semantics (e.g., <nav focusgroup="toolbar">) or an explicit role (e.g., <div focusgroup="toolbar" role="navigation">), the existing role is preserved and only the focus navigation behavior is applied.

    + +

    Role inference never overrides explicit author-defined roles or meaningful native-element semantics. It also does not infer variant roles like menuitemcheckbox; such roles can be specified explicitly by the author.

    + +
    Focus Handling
    + + +
    Directional Navigation
    + +
    +

    When a user requests Directional Navigation and focus is within a focusgroup scope, the user agent must run these steps:

    + +
      +
    1. If the navigation request is not in an allowed axis given the focusgroup owner's modifiers, do nothing.
    2. +
    3. Let direction be the spatial direction requested (e.g., up, down, left, right) as determined by the user agent and input device.
    4. +
    5. Let owner be the focusgroup owner.
    6. +
    7. Let currentItem be the currently focused focusgroup item.

    8. +
    9. Let items be all focusgroup items in tree order.

    10. +
    11. Determine the nextItem by finding the nearest item in tree order in the direction.

    12. +
    13. If no nextItem is found and the wrap token is present, wrap to the first item in the specified direction. Otherwise, do nothing.

    14. +
    15. If a nextItem is identified, run the focusing steps for it.

    16. +
    +
    + +
    Sequential Navigation and Guaranteed Tab Stop
    + +

    A focus group must have at least one guaranteed tab stop. When elements opt-out of a focusgroup using focusgroup="none", they divide the focusgroup for sequential focus navigation purposes, creating one tab stop per focusgroup segment.

    +
    +

    When a user requests sequential focus navigation into a focus group, the user agent must run these steps:

    + +
      +
    1. Let direction be "forward" or "backward" as determined by the user agent and input device (for example, Tab or Shift+Tab).

    2. + +
    3. Let entryElement be the element from which focus is entering the focusgroup.

    4. + +
    5. Let focusgroupSegment be the set of focusgroup items in the nearest focusgroup scope that are reachable without crossing any opted-out elements in tree order from entryElement in the direction of navigation.

    6. + +
    7. If focusgroupSegment has a last focused item and the no-memory token is not present, and the last focused item is within focusgroupSegment, then let target be the last focused item.

    8. + +
    9. Otherwise, let target be the first item that would be focused according to the following priority order: first, the lowest positive tabindex value; then elements with tabindex="0" or implicit focusability; and finally, as the lowest priority, elements with tabindex="-1". Within each priority level, prioritize the nearest to the entryElement in tree order.

    10. + +
    11. Run the focusing steps for target. If the no-memory token is not present, store target as the last focused item of the focusgroup.

    12. +
    +
    + +
    +

    This example shows how opted-out elements create multiple focusgroup entry points:

    + +
    <div focusgroup="toolbar wrap" aria-label="Text formatting">
    +  <button type="button" tabindex="-1">Bold</button>
    +  <button type="button" tabindex="-1">Italic</button>
    +  <span focusgroup="none" aria-label="Help group">
    +    <button type="button">Help</button>
    +    <button type="button">Shortcuts</button>
    +  </span>
    +  <button type="button" tabindex="-1">Underline</button>
    +</div>
    + +

    Sequential focus navigation behavior:

    +
      +
    1. Entering from before: Pressing Tab focuses "Bold" (first focusgroup item).
    2. +
    3. Tab from "Bold": Focuses "Help" (first opted-out element in sequential order).
    4. +
    5. Tab from "Help": Focuses "Shortcuts" (normal sequential navigation within opted-out subtree).
    6. +
    7. Tab from "Shortcuts": Re-enters the focusgroup, focusing "Underline" (only considering focusgroup items that follow "Shortcuts" in DOM order).
    8. +
    9. Shift+Tab from "Help": Moves focus back to the focusgroup segment before "Help", applying the guaranteed tab stop rules only to focusgroup items that precede "Help" in DOM order.
    10. +
    + +

    Arrow key navigation is unaffected by opted-out elements: pressing the right arrow on "Italic" moves focus directly to "Underline", treating the opted-out span as if it doesn't exist for arrow navigation purposes.

    +
    + +
    +

    This example shows a tablist with manual activation, wrap-around navigation, and disabled memory:

    + +
    <div focusgroup="toolbar wrap no-memory">
    +  <button id="tab-1" tabindex="-1">macOS</button>
    +  <button id="tab-2" tabindex="0">Windows</button>
    +  <button id="tab-3" tabindex="-1">Linux</button>
    +  </div>
    + +

    Sequential focus navigation behavior:

    +
      +
    1. Entering from before: Pressing Tab focuses "Windows".
    2. +
    3. Entering from after: Pressing Shift+Tab focuses "Windows"
    4. +
    +
    + +
    Key Conflict Elements
    + +

    A key conflict element is a focusgroup item that consumes arrow key events for its own functionality, creating a conflict with focusgroup navigation. Key conflict elements include:

    + + + +

    When focus is within a key conflict element, the element's native behavior takes precedence over focusgroup navigation. To ensure users can still navigate to other focusgroup items, user agents must provide escape behavior for native key conflict elements.

    + +
    +

    When the user activates the escape behavior by pressing Tab or Shift+Tab from within a key conflict element, the user agent must run these steps:

    + +
      +
    1. Let direction be "forward" if the user pressed Tab, or "backward" if the user pressed Shift+Tab.

    2. + +
    3. Let keyConflictElement be the currently focused key conflict element.

    4. + +
    5. Let candidates be all focusgroup items in the same focusgroup scope as keyConflictElement, excluding keyConflictElement itself.

    6. + +
    7. If direction is "forward", let eligibleItems be all items in candidates that follow keyConflictElement in tree order.

    8. + +
    9. If direction is "backward", let eligibleItems be all items in candidates that precede keyConflictElement in tree order.

    10. + +
    11. Among eligibleItems, let target be the first item that would be focused according to the following priority order: first, the lowest positive tabindex value; then elements with tabindex="0" or implicit focusability; and finally, as the lowest priority, elements with tabindex="-1". Within each priority level, order by tree order.

    12. + +
    13. If target is not null, run the focusing steps for target. + +

    14. Otherwise, follow the normal sequential focus navigation rules.

    15. +
    +
    + +
    +

    In this toolbar example, the search input is a key conflict element:

    + +
    <div focusgroup="toolbar" aria-label="Text formatting">
    +  <button type="button" tabindex="-1">Bold</button>
    +  <button type="button" tabindex="-1">Italic</button>
    +  <div>
    +    <input type="text" placeholder="Search" /> <!-- Key conflict element -->
    +    <button tabindex="-1">Go</button>
    +  </div>
    +  <button type="button" tabindex="-1">Save</button>
    +  <button type="button" tabindex="-1">Print</button>
    +</div>
    + +

    When focus is within the search input:

    + +
    + +
    +

    This example shows how authors can control escape behavior using tabindex values:

    + +
    <div focusgroup="toolbar" aria-label="Text formatting">
    +  <button type="button" tabindex="-1">Bold</button>
    +  <button type="button" tabindex="-1">Italic</button>
    +  <div>
    +    <input type="text" placeholder="Search" /> <!-- Key conflict element -->
    +    <button tabindex="-1">Go</button> <!-- Higher priority -->
    +  </div>
    +  <button type="button" tabindex="0">Save</button> <!-- Lowest priority -->
    +  <button type="button" >Print</button> <!-- Lower priority -->
    +</div>
    + +

    In this modified example, the priority order for escape behavior is:

    + +
    + +
    Scrolling Interactions
    + +

    Focusgroups must coexist with scrolling behavior, as arrow keys are commonly used for both focus navigation and scrolling. The priority and interaction between these behaviors depends on the context.

    + +

    When a focusgroup is contained within a scrollable region:

    + + +

    Since focusgroup navigation takes priority over scrolling, take care when constructing large focusgroups to avoid situations where content could be missed when jumping from one item to another.

    + +

    When a scrollable element is contained within a focusgroup, the behavior depends on whether there's a conflict between the focusgroup's arrow key handling and the scrollable element's needs:

    + + +
    +

    This example shows a focusgroup with restricted axis containing a scrollable region:

    + +
    <div style="height: 200px; overflow: auto;">
    +  <div focusgroup="listbox block">
    +    <div tabindex="0" aria-selected="true">Item 1</div>
    +    <div tabindex="-1" aria-selected="false">Item 2</div>
    +    <div tabindex="-1" aria-selected="false">Item 3</div>
    +    <!-- Items 4-97 would be here, creating a long scrollable list -->
    +    <div tabindex="-1" aria-selected="false">Item 98</div>
    +    <div tabindex="-1" aria-selected="false">Item 99</div>
    +    <div tabindex="-1" aria-selected="false">Item 100</div>
    +  </div>
    +</div>
    + +

    In this example:

    + +
    +

    Assigning keyboard shortcuts