DOM manipulation utilities for Material Components providing cross-browser compatibility, focus management, and accessibility features.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Cross-browser keyboard event normalization utilities that provide consistent key handling across different browsers and platforms.
Normalized string values for common keyboard keys.
const KEY: {
readonly UNKNOWN: 'Unknown';
readonly BACKSPACE: 'Backspace';
readonly ENTER: 'Enter';
readonly SPACEBAR: 'Spacebar';
readonly PAGE_UP: 'PageUp';
readonly PAGE_DOWN: 'PageDown';
readonly END: 'End';
readonly HOME: 'Home';
readonly ARROW_LEFT: 'ArrowLeft';
readonly ARROW_UP: 'ArrowUp';
readonly ARROW_RIGHT: 'ArrowRight';
readonly ARROW_DOWN: 'ArrowDown';
readonly DELETE: 'Delete';
readonly ESCAPE: 'Escape';
readonly TAB: 'Tab';
};Returns a normalized string for keyboard events that works consistently across browsers.
/**
* Returns the normalized string for a navigational action derived from KeyboardEvent
* to be standard across browsers
* @param evt - The keyboard event to normalize
* @returns Normalized key string or 'Unknown' if not recognized
*/
function normalizeKey(evt: KeyboardEvent): string;Determine if a keyboard event represents a navigation action.
/**
* Returns whether the event is a navigation event (Page Up, Page Down, Home, End, Arrow keys)
* @param evt - The keyboard event to test
* @returns True if the event is a navigation event
*/
function isNavigationEvent(evt: KeyboardEvent): boolean;import { KEY, normalizeKey } from '@material/dom/keyboard';
document.addEventListener('keydown', (event) => {
const key = normalizeKey(event);
switch (key) {
case KEY.ENTER:
case KEY.SPACEBAR:
// Activate element
handleActivation();
break;
case KEY.ESCAPE:
// Close modal/menu
closeModal();
break;
case KEY.ARROW_UP:
case KEY.ARROW_DOWN:
// Navigate list
navigateList(key === KEY.ARROW_UP ? -1 : 1);
break;
}
});import { isNavigationEvent, normalizeKey, KEY } from '@material/dom/keyboard';
function handleKeydown(event: KeyboardEvent) {
if (isNavigationEvent(event)) {
event.preventDefault();
const key = normalizeKey(event);
switch (key) {
case KEY.ARROW_LEFT:
case KEY.ARROW_RIGHT:
handleHorizontalNavigation(key === KEY.ARROW_RIGHT ? 1 : -1);
break;
case KEY.ARROW_UP:
case KEY.ARROW_DOWN:
handleVerticalNavigation(key === KEY.ARROW_DOWN ? 1 : -1);
break;
case KEY.HOME:
focusFirst();
break;
case KEY.END:
focusLast();
break;
case KEY.PAGE_UP:
case KEY.PAGE_DOWN:
handlePageNavigation(key === KEY.PAGE_DOWN ? 1 : -1);
break;
}
}
}import { KEY, normalizeKey, isNavigationEvent } from '@material/dom/keyboard';
class MenuComponent {
private currentIndex = 0;
private menuItems: HTMLElement[] = [];
handleKeydown(event: KeyboardEvent) {
const key = normalizeKey(event);
if (key === KEY.ESCAPE) {
this.closeMenu();
return;
}
if (key === KEY.ENTER || key === KEY.SPACEBAR) {
this.selectCurrentItem();
return;
}
if (isNavigationEvent(event)) {
event.preventDefault();
switch (key) {
case KEY.ARROW_UP:
this.moveFocus(-1);
break;
case KEY.ARROW_DOWN:
this.moveFocus(1);
break;
case KEY.HOME:
this.focusItem(0);
break;
case KEY.END:
this.focusItem(this.menuItems.length - 1);
break;
}
}
}
private moveFocus(direction: number) {
this.currentIndex = Math.max(0, Math.min(
this.menuItems.length - 1,
this.currentIndex + direction
));
this.focusItem(this.currentIndex);
}
}import { KEY, normalizeKey } from '@material/dom/keyboard';
function handleFormKeydown(event: KeyboardEvent) {
const key = normalizeKey(event);
if (key === KEY.ENTER) {
const target = event.target as HTMLElement;
if (target.tagName === 'TEXTAREA') {
// Allow line breaks in textarea
return;
}
if (target.tagName === 'INPUT') {
// Submit form or move to next field
event.preventDefault();
submitFormOrFocusNext();
}
}
if (key === KEY.ESCAPE) {
// Cancel form editing
cancelFormEditing();
}
}The keyboard utilities handle differences between browsers:
KeyboardEvent.key property when availableKeyboardEvent.keyCode propertyThe normalization handles these browser differences:
| Key | Modern (event.key) | Legacy (event.keyCode) |
|---|---|---|
| Enter | 'Enter' | 13 |
| Space | ' ' → 'Spacebar' | 32 |
| Arrow Up | 'ArrowUp' | 38 |
| Arrow Down | 'ArrowDown' | 40 |
| Escape | 'Escape' | 27 |
The following keys are considered navigation events:
PAGE_UP, PAGE_DOWN - Page navigationHOME, END - Document/container boundariesARROW_LEFT, ARROW_RIGHT - Horizontal navigationARROW_UP, ARROW_DOWN - Vertical navigationKeys that aren't recognized return KEY.UNKNOWN to allow graceful handling of: