AncientSwordRage
AncientSwordRage

Reputation: 7635

Should material-ui's FormControl pass events to the underlying input to be accessible?

I have a component that uses FormControl. I'm trying to make sure it's accessible, and leaning on things like role and aria-label in the tests to help with that.

Here is the rough outline of the component:

const MySearch = ({searchText, setSearch}) => {
  const inputRef = useRef();
  return (<div class="some classes">
    <FormControl role="search" aria-label="My Search Box" fullWidth>
      <InputLabel>
        <IconSearch />
        Find Foo
      </InputLabel>
      <Input
        inputRef={inputRef}
        onChange={event => setSearchText(event.target.value)}
        value={searchText}
        endAdornment={searchText &&
          <InputAdornment position="end">
            <IconButton
              arial-label="Clear Search"
              onClick={() => {
                setSearchText('');
                if (inputRef.current) inputRef.current.focus();
              }}
            >
              <IconClear />
            </IconButton>
          </InputAdornment>
        } 
      />
    </FormControl>
   </div>
  )

When I use this test code to type 'i' into the input box, like so:

await userEvent.type(screen.getByRole('search'), 'i');

I do not get any event firing, and I have been informed by a colleague that directly selecting the input (by putting a role, label of testid) will work but none of use are sure if that is the correct place to select for accessibility purposes.

The w3 spec for role="search" says it's for the region (and I note that role="searchbox" exists) but I'm not clear what this means in terms of expected behaviour when navigating here, or it's accessibility.

Neither the material-ui FormControl api docs or the demos mention roles.

Putting a click or change listener on the FormControl itself does fire on the webpage, but doesn't fire at all in the test - maybe my use of await userEvent.type(screen.getByRole('search'), 'i'); is wrong.

Ultimately, while I will direct my test to point at the search input for now, is it not the right behaviour that clicking the FormControl should mean the event is captured by the FormControl and then 'passed' down to the input, before bubbling back up (see What is event bubbling and capturing?)?

What is the correct behaviour of the FormControl so that it is accessible? I found Pass click event to nested component - React | Material-UI which seems related, but doesn't cover accessibility or FormControl which I was expecting to behave differently

Upvotes: 0

Views: 362

Answers (1)

Andy
Andy

Reputation: 6170

No, they should not.

  1. Events may bubble up, but never down in the hierarchy
  2. Only the input role is expected to accept user input, not the search role.

The search role is a landmark role.

A perceivable section containing content that is relevant to a specific, author-specified purpose and sufficiently important that users will likely want to be able to navigate to the section easily and to have it listed in a summary of the page. Such a page summary could be generated dynamically by a user agent or assistive technology.

It only serves navigation, and assistive technology will allow users to jump there and continue reading.

Assistive technologies SHOULD enable users to quickly navigate to landmark regions.

So it is definitely very helpful that you offer this landmark, but it does not apply any semantics on the input. You should also add the searchbox role, ideally while applying the First Rule of ARIA and using an HTML input type.

<input type="search">

I do not know the library you are using to provide the correct code here.

About the events, I believe there is a confusion between dispatching and listening to events. While you can bind listeners to the parent FormField, which might receive bubbled events from its input, dispatching an input event on it will not effect the input, even in production code.

See Event bubbling and capture on MDN

Upvotes: 1

Related Questions