or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

announce.mdevents.mdfocus-trap.mdindex.mdkeyboard.mdponyfill.md

keyboard.mddocs/

0

# Keyboard Utilities

1

2

Cross-browser keyboard event normalization utilities that provide consistent key handling across different browsers and platforms.

3

4

## Capabilities

5

6

### Key Constants

7

8

Normalized string values for common keyboard keys.

9

10

```typescript { .api }

11

const KEY: {

12

readonly UNKNOWN: 'Unknown';

13

readonly BACKSPACE: 'Backspace';

14

readonly ENTER: 'Enter';

15

readonly SPACEBAR: 'Spacebar';

16

readonly PAGE_UP: 'PageUp';

17

readonly PAGE_DOWN: 'PageDown';

18

readonly END: 'End';

19

readonly HOME: 'Home';

20

readonly ARROW_LEFT: 'ArrowLeft';

21

readonly ARROW_UP: 'ArrowUp';

22

readonly ARROW_RIGHT: 'ArrowRight';

23

readonly ARROW_DOWN: 'ArrowDown';

24

readonly DELETE: 'Delete';

25

readonly ESCAPE: 'Escape';

26

readonly TAB: 'Tab';

27

};

28

```

29

30

### Key Normalization

31

32

Returns a normalized string for keyboard events that works consistently across browsers.

33

34

```typescript { .api }

35

/**

36

* Returns the normalized string for a navigational action derived from KeyboardEvent

37

* to be standard across browsers

38

* @param evt - The keyboard event to normalize

39

* @returns Normalized key string or 'Unknown' if not recognized

40

*/

41

function normalizeKey(evt: KeyboardEvent): string;

42

```

43

44

### Navigation Event Detection

45

46

Determine if a keyboard event represents a navigation action.

47

48

```typescript { .api }

49

/**

50

* Returns whether the event is a navigation event (Page Up, Page Down, Home, End, Arrow keys)

51

* @param evt - The keyboard event to test

52

* @returns True if the event is a navigation event

53

*/

54

function isNavigationEvent(evt: KeyboardEvent): boolean;

55

```

56

57

## Usage Examples

58

59

### Basic Key Handling

60

61

```typescript

62

import { KEY, normalizeKey } from '@material/dom/keyboard';

63

64

document.addEventListener('keydown', (event) => {

65

const key = normalizeKey(event);

66

67

switch (key) {

68

case KEY.ENTER:

69

case KEY.SPACEBAR:

70

// Activate element

71

handleActivation();

72

break;

73

case KEY.ESCAPE:

74

// Close modal/menu

75

closeModal();

76

break;

77

case KEY.ARROW_UP:

78

case KEY.ARROW_DOWN:

79

// Navigate list

80

navigateList(key === KEY.ARROW_UP ? -1 : 1);

81

break;

82

}

83

});

84

```

85

86

### Navigation Event Handling

87

88

```typescript

89

import { isNavigationEvent, normalizeKey, KEY } from '@material/dom/keyboard';

90

91

function handleKeydown(event: KeyboardEvent) {

92

if (isNavigationEvent(event)) {

93

event.preventDefault();

94

95

const key = normalizeKey(event);

96

switch (key) {

97

case KEY.ARROW_LEFT:

98

case KEY.ARROW_RIGHT:

99

handleHorizontalNavigation(key === KEY.ARROW_RIGHT ? 1 : -1);

100

break;

101

case KEY.ARROW_UP:

102

case KEY.ARROW_DOWN:

103

handleVerticalNavigation(key === KEY.ARROW_DOWN ? 1 : -1);

104

break;

105

case KEY.HOME:

106

focusFirst();

107

break;

108

case KEY.END:

109

focusLast();

110

break;

111

case KEY.PAGE_UP:

112

case KEY.PAGE_DOWN:

113

handlePageNavigation(key === KEY.PAGE_DOWN ? 1 : -1);

114

break;

115

}

116

}

117

}

118

```

119

120

### Menu Navigation

121

122

```typescript

123

import { KEY, normalizeKey, isNavigationEvent } from '@material/dom/keyboard';

124

125

class MenuComponent {

126

private currentIndex = 0;

127

private menuItems: HTMLElement[] = [];

128

129

handleKeydown(event: KeyboardEvent) {

130

const key = normalizeKey(event);

131

132

if (key === KEY.ESCAPE) {

133

this.closeMenu();

134

return;

135

}

136

137

if (key === KEY.ENTER || key === KEY.SPACEBAR) {

138

this.selectCurrentItem();

139

return;

140

}

141

142

if (isNavigationEvent(event)) {

143

event.preventDefault();

144

145

switch (key) {

146

case KEY.ARROW_UP:

147

this.moveFocus(-1);

148

break;

149

case KEY.ARROW_DOWN:

150

this.moveFocus(1);

151

break;

152

case KEY.HOME:

153

this.focusItem(0);

154

break;

155

case KEY.END:

156

this.focusItem(this.menuItems.length - 1);

157

break;

158

}

159

}

160

}

161

162

private moveFocus(direction: number) {

163

this.currentIndex = Math.max(0, Math.min(

164

this.menuItems.length - 1,

165

this.currentIndex + direction

166

));

167

this.focusItem(this.currentIndex);

168

}

169

}

170

```

171

172

### Form Validation

173

174

```typescript

175

import { KEY, normalizeKey } from '@material/dom/keyboard';

176

177

function handleFormKeydown(event: KeyboardEvent) {

178

const key = normalizeKey(event);

179

180

if (key === KEY.ENTER) {

181

const target = event.target as HTMLElement;

182

183

if (target.tagName === 'TEXTAREA') {

184

// Allow line breaks in textarea

185

return;

186

}

187

188

if (target.tagName === 'INPUT') {

189

// Submit form or move to next field

190

event.preventDefault();

191

submitFormOrFocusNext();

192

}

193

}

194

195

if (key === KEY.ESCAPE) {

196

// Cancel form editing

197

cancelFormEditing();

198

}

199

}

200

```

201

202

## Cross-Browser Compatibility

203

204

The keyboard utilities handle differences between browsers:

205

206

### Modern Browsers

207

- Use the standard `KeyboardEvent.key` property when available

208

- Return consistent string values per W3C specification

209

210

### Legacy Browsers

211

- Fall back to `KeyboardEvent.keyCode` property

212

- Map numeric key codes to standard key strings

213

- Handle vendor-specific key code variations

214

215

### Key Mapping

216

217

The normalization handles these browser differences:

218

219

| Key | Modern (`event.key`) | Legacy (`event.keyCode`) |

220

|-----|---------------------|-------------------------|

221

| Enter | `'Enter'` | `13` |

222

| Space | `' '``'Spacebar'` | `32` |

223

| Arrow Up | `'ArrowUp'` | `38` |

224

| Arrow Down | `'ArrowDown'` | `40` |

225

| Escape | `'Escape'` | `27` |

226

227

### Navigation Keys

228

229

The following keys are considered navigation events:

230

- `PAGE_UP`, `PAGE_DOWN` - Page navigation

231

- `HOME`, `END` - Document/container boundaries

232

- `ARROW_LEFT`, `ARROW_RIGHT` - Horizontal navigation

233

- `ARROW_UP`, `ARROW_DOWN` - Vertical navigation

234

235

### Unknown Keys

236

237

Keys that aren't recognized return `KEY.UNKNOWN` to allow graceful handling of:

238

- Unmapped key codes in legacy browsers

239

- New keys not in the normalization table

240

- Platform-specific keys