Files
site-builder/craft/src/utils/a11y.ts
T

37 lines
1.2 KiB
TypeScript
Raw Normal View History

import type { KeyboardEvent } from 'react';
export interface ClickableProps {
role: 'button';
tabIndex: number;
onClick: () => void;
onKeyDown: (e: KeyboardEvent) => void;
}
/**
* Props to spread onto a non-interactive element (typically a `<div>`) that
* acts like a button (e.g. a clickable list row or grid tile), so it
* becomes keyboard-operable: `role="button"`, a tab stop, and Enter/Space
* activation in addition to the existing click behavior.
*
* Usage: `<div {...clickableProps(() => doThing())}>...</div>`
*/
export function clickableProps(onActivate: () => void): ClickableProps {
return {
role: 'button',
tabIndex: 0,
onClick: onActivate,
onKeyDown: (e: KeyboardEvent) => {
// Ignore keydown events that bubbled up from a nested interactive
// element (e.g. a child <button>). Handling only events targeted at
// this element lets the browser's native "click" synthesis for a
// focused child control proceed instead of being hijacked by the
// row's own Enter/Space activation.
if (e.target !== e.currentTarget) return;
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
onActivate();
}
},
};
}