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
Open your project in any browser, for instance, Chrome.
Set focus on any card element via pressing Tab on Windows/macOS.
Press Space key.
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>
);
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.
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
andkeyup
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
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"
andtabindex
attributes from the card container, as well as thecursor: pointer
property. We need this container only for styling purposes. Actually, you can remove the whole container and setwidth
andposition
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 setid
for hidden spans. IDs for every card button should be unique. Pairsaria-describedby
andid
should contain exactly the same tokens.Something like this:
Reset button styles:
Styles for hint for the button:
Alternatively, use the
hidden
HTML attribute.Third step. Let's cast CSS magic, and create the bigger clicable area.
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:
Screencasts and screenshots
The custom button without the name in the a11y tree preview in Chrome.
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: