Dismiss a Material UI Tooltip by Pressing Escape

Viewed 1042

I am working on accessibility in an app and one of the WCAG requirements is that tooltips are dismissable with esc. This isn't automatically available in the Material UI <Tooltip> component. I know that is is coming in version 5 of Material UI but I have been asked to find a workaround before we uplift to a new version (we are using v4.5.2 right now).

I have investigated using a <ClickAwayListener> and adding onKeyPressed to the <Tooltip> but neither of those seem to have worked.

My code is below

import React from 'react';
import { Tooltip } from '@material-ui/core';

const AccessibleTooltip = (tooltipText, tooltipPlacement, innerElement) => (
  <Tooltip
    interactive
    arrow
    title={tooltipText}
    placement={tooltipPlacement}
    aria-label={tooltipText}
  >
    {innerElement}
  </Tooltip>
);

export default AccessibleTooltip;

I am fairly new to React and Material so some guidance/pointers would be much appreciated

1 Answers

You can easily do that if you take control of the Tooltip's open state

const AccessibleTooltip = (props) => {
  const { text, ...rest } = props;
  const [open, setOpen] = React.useState(false);
  const onOpen = () => setOpen(true);
  const onClose = () => setOpen(false);

  const handler = React.useCallback((e) => {
    console.log("keydown", e.key);
    if (e.key === "Escape") {
      onClose();
    }
  }, []);

  useEventListener("keydown", handler);

  return (
    <Tooltip
      open={open}
      onOpen={onOpen}
      onClose={onClose}
      interactive
      arrow
      title={text}
      aria-label={text}
      {...rest}
    />
  );
};

Where useEventListener is a custom hook that adds and removes event listener when the component mounts and unmounts respectively

function useEventListener(eventName, handler, element = window) {
  const savedHandler = React.useRef();

  React.useEffect(() => {
    savedHandler.current = handler;
  }, [handler]);

  React.useEffect(() => {
    const isSupported = element && element.addEventListener;
    if (!isSupported) return;

    const eventListener = (event) => savedHandler.current(event);

    element.addEventListener(eventName, eventListener);

    return () => {
      element.removeEventListener(eventName, eventListener);
    };
  }, [eventName, element]);
}

Live Demo

Edit Material-UI - Tooltip Esc To Close

Related