nerucheva / ashstone-test-task

https://nerucheva.github.io/ashstone-test-task/
0 stars 0 forks source link

Keyboard interaction: Open popovers with keyboard & add names for buttons #12

Open TatianaFokina opened 3 months ago

TatianaFokina commented 3 months ago

Description & explanation

Keyboard users can't interact with the card component by pressing Space or Enter. The reason is you create a custom button component and it doesn't support keydown and keyup events as native buttons does.

The second problem is the custom button element hasn't got a name. Screen reader announce only the role, and users should guess what this button does. At the same time, the screen reader continues to read the whole card's content without pause.

Type of issue

Serious.

How to reproduce

  1. Open your project in any browser, for instance, Chrome.
  2. Set focus on any card element via pressing Tab on Windows/macOS.
  3. Press Space key.
  4. Press Enter key.

On macOS you need to enable the keyboard navigation first. Сhoose Apple menu > System Settings, then click Keyboard in the sidebar (you may need to scroll down). Turn on “Keyboard navigation” on the right.

Turn on any screen reader and repeat all steps.

How to fix

Create a button with extra description inside the card component and use the CSS trick with pseudo-elements.

First step: Remove the role="button" and tabindex attributes from the card container, as well as the cursor: pointer property. We need this container only for styling purposes. Actually, you can remove the whole container and set width and position for the article element (you don't use BEM notation, so it's not considered a crime!)

Second step. Place a real button inside the card component. Your case isn't typical, unlike cards with links inside when you use heading content as a name for link.

So, the only solution that I can see for now is using the card's heading as a parent for button with an extra hidden description “Open in modal window” for screen reader users. Then they will know what this button do that's pretty important for that kind of micro text.

How to add an extra description for every button? Add the aria-describedby attribute to a button and set id for hidden spans. IDs for every card button should be unique. Pairs aria-describedby and id should contain exactly the same tokens.

Something like this:

export const Card: React.FC<Post> = ({
  img,
  img_2x,
  button,
  span,
  {/* and so on */}
}) => (
  <article className={styles.card}>
    <img className={styles.img} src={img} srcSet={`${img_2x} 2x`} alt={title} />
    <span className={styles.tags}>{tags}</span>
    <h2
      className={styles.title}
    >
      <button
        className={styles.cardButton}
        aria-describedby={id}
      >
        {title}
      </button>
    </h2>
    <span
      className={styles.hint}
      id={id}
    >
      {hint} {/* text 'Open in modal window' */}
    </span>
    {/* etc. */}
  </article>
);

Reset button styles:

.cardButton {
  border: 0;
  padding: 0;
  margin: 0;
  background: transparent;
  text-align: unset;
  font-weight: inherit;
  font-family: inherit;
  font-size: inherit;
}

Styles for hint for the button:

.hint {
  display: none;
}

Alternatively, use the hidden HTML attribute.

Third step. Let's cast CSS magic, and create the bigger clicable area.

/* or .postButton if you don't want remove this element */
.card:after {
  content: "";
  position: absolute;
}
.cardButton:after {
  content: "";
  position: absolute;
  inset: 0;
}

Profit! The only issue you'll face is focus styles. If you want to add a focus outline for the whole card, add it for the card element. Something like this:

.card:focus-within {
 outline: auto;
}

Screencasts and screenshots

The custom button without the name in the a11y tree preview in Chrome.

image

How NVDA announce the card component now:

https://github.com/nerucheva/ashstone-test-task/assets/17615202/583b4850-7f67-4bcf-b727-cbf14f931e51

How NVDA will announce the refine card component:

https://github.com/nerucheva/ashstone-test-task/assets/17615202/7b08f77e-9f83-4a41-ad77-70db10aa4e0b

Axe:

image