IBMa / equal-access

IBM Equal Access Accessibility Checker contains tools to automate accessibility checking from a browser or in a continuous development/build environment
https://www.ibm.com/able/toolkit/tools#develop
Apache License 2.0
635 stars 82 forks source link

[Rule_Bug]: The tabbable element’s role ‘region’ is not a widget role #2054

Open Mahalakshmivignesh opened 1 month ago

Mahalakshmivignesh commented 1 month ago

Project

other

Browser

Chrome

Operating System

MacOS

Automated testing tool and ruleset

IBM Equal accessibility checker

Assistive technology

No response

Description

In my UI page, i have two

that are scrollable depending on the content length. the accessibility error that i got ‘The scrollable element
with non-interactive content is not tabbable’ as fixed by adding tab index to both of these div. But only for the div in the right hand side, i am getting new accessibility error ’The tabbable element’s role ‘region’ is not a widget role’.

  • What would be the reason i get this error only for one of the scrollable panes?
  • If region is not a valid widget role, what else should i give?
  • any other suggestion on fixing this error?

image

Steps to reproduce

Project specific. css definitions are as below: .inputSchemaJSON { position: relative; float: left; height: 332px; max-height: 332px; width: 50%; border-right: 1px solid #E0E0E0; border-top: 1px solid #E0E0E0; padding-left: 20px; padding-right: 20px; padding-bottom: 20px; overflow-y: auto; }

.outputSchemaJSON { position: relative; float: right; max-height: 332px; height: 332px; width: 50%; border-top: 1px solid #E0E0E0; padding-left: 20px; padding-right: 20px; padding-bottom: 20px; overflow-y: auto !important;

slack discussion link - https://ibm-systems-z.slack.com/archives/C036P1CTN/p1726218784246219

philljenkins commented 1 month ago

What would be the reason i get this error only for one of the scrollable panes?

The left region has overflow-y: auto;, and the right (second) region has overflow-y: auto !important;. Without access to the full page, it’s not clear if this is dynamically set or not.

Besides using !important for standard reasons, such as overriding other "inherited" or parent/child CSS settings and avoiding bugs in non-Chromium IE (neither may not be applicable in this case), it's also considered to be a "good trick" to automatically force the browser to display the otherwise disabled vertical scroll bar even when the region is not vertically very long. Accessibility is impacted when scroll bars appear or are absent depending on the content.

!important also prevents your pages from shifting left or right when user either goes from a shorter page to a longer one or expands/collapses a tab or section. Without access to the page we can't test this.

There several RuleIDs at play, two of which are:

  1. element_scrollable_tabbable: Scrollable elements should be tabbable or contain tabbable content. The scrollable element <{0}> with non-interactive content is not tabbable
  2. element_tabbable_role_valid: A tabbable element must have a valid widget role. The tabbable element's role '{0}' is not a widget role

Depending on the dynamic state of the page and scrollable regions when loaded, a rule will flag an error on regions that have scroll bars but that do not contain keyboard tabbable content (or tab index) because users in some browsers, such as Firefox (if I remember correctly), will not be able to navigate using the keyboard tab key to the region and then use the keyboard to scroll the content into view. The opposite is also true, which I think is your case, that tabbing to a region that contains non-interactive content that doesn’t need to be scrollable or the role (widget type) is wrong/unknown will confuse the user.

The Learn more link includes this explanation:

… When users reach elements by tabbing with the keyboard, the element's role provides context about the expected interaction, and assistive technologies like screen readers can provide additional information about ways to interact. The only elements that should be in the tab order should be operable widgets. Inoperable elements, such as headings, can be given focus by developers; however, they should not be tabbable by the user. …
The Checker also detects content blocks that get keyboard focus to enable scrolling of the area using arrow keys when coding CSS overflow: scroll or overflow: auto. Both attributes could be valid. However, if the element should not be operable with the keyboard, then it should not be tabbable and get keyboard focus.

@Mahalakshmivignesh

  • Why is the design set to always include the scroll bar on the second region?
  • Can you provide access/link to the page so we can dynamic test and check rule logic?
Mahalakshmivignesh commented 1 month ago

@philljenkins @shunguoy - adding additional details. I believe it is not always set to include scroll bar. I am saying this coz, i see the same style is being used in other tabs as well, but i dont see a scroll bar there. I am sharing the details here. i see 4 tabs in my UI. Apart from the first tab all the other three uses same style. I am giving screenshots of all 4 tabs and we can see that the scrollbar is not present in all the tabs. image image image image

This is wat i have in my logic:

let currentSchemaView = [];
    if (this.state.currentSchemaViewType == constants.SCHEMA_VIEW_TYPES[0]) {
        currentSchemaView.push(<div key={0} className={styles2.inputSchemaTable}>
                                    <Table
                                        columns={TOP_VIEW_CONTAINER_COLUMN_HEADERS}
                                        data={mapDataToTableColumns(inputDataSchemaFields, 'Schema')}
                                        sortColumn="name"
                                        initialSortDirection={constants.SORT_DIRECTION_ASC}
                                        minRows={constants.MAX_TABLE_ROWS}
                                        noContentText="no input schema found">
                                    </Table>
                                </div>);
        currentSchemaView.push(<div key={1} className={styles2.outputSchemaTable}>
                                    <Table
                                        columns={TOP_VIEW_CONTAINER_COLUMN_HEADERS}
                                        data={mapDataToTableColumns(outputDataSchemaFields, 'Schema')}
                                        sortColumn="name"
                                        initialSortDirection={constants.SORT_DIRECTION_ASC}
                                        minRows={constants.MAX_TABLE_ROWS}
                                        noContentText="no output schema found">
                                    </Table>
                                </div>);
    } else if (this.state.currentSchemaViewType == constants.SCHEMA_VIEW_TYPES[1]) {
        currentSchemaView.push(<div key={0} className={styles2.inputSchemaJSON}>
                                    <pre>{_.unescape(getJsonSchema(inputDataSchema, 'input'))}</pre>
                                </div>);
        currentSchemaView.push(<div key={1} className={styles2.outputSchemaJSON}>
                                    <pre>{_.unescape(getJsonSchema(outputDataSchema, 'output'))}</pre>
                                </div>);
    } else if (this.state.currentSchemaViewType == constants.SCHEMA_VIEW_TYPES[2]) {
        currentSchemaView.push(
            <div key={0} className={styles2.inputSchemaJSON} tabIndex='0' role="region" aria-label="JSON Schema input">
                <pre>{_.unescape(inputJsonSchema)}</pre>
            </div>
        );
        currentSchemaView.push(
            <div key={1} className={styles2.outputSchemaJSON} tabIndex='0' role="region" aria-label="JSON Schema output">
                <pre>{_.unescape(outputJsonSchema)}</pre>
            </div>
        );
    } else if (this.state.currentSchemaViewType == constants.SCHEMA_VIEW_TYPES[3]) {
      currentSchemaView.push(
          <div key={0} className={styles2.inputSchemaJSON}>
              <pre>{_.unescape(inputCopybook)}</pre>
          </div>
      );
      currentSchemaView.push(
          <div key={1} className={styles2.outputSchemaJSON}>
              <pre>{_.unescape(outputCopybook)}</pre>
          </div>
      );
  }
shunguoy commented 1 month ago

Triage: revisit the auto scroll calculation to see why it didn't cover the test case in the rule element_tabbable_role_valid line 75-78.