or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

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

focus-trap.mddocs/

0

# Focus Management

1

2

Focus trapping utility for managing focus within modal components like dialogs, drawers, and popups. Ensures keyboard navigation stays within the modal and provides accessible focus management.

3

4

## Capabilities

5

6

### FocusTrap Class

7

8

Utility class that traps focus within a given root element, intended for modal components.

9

10

```typescript { .api }

11

/**

12

* Utility to trap focus in a given root element, e.g. for modal components such

13

* as dialogs. The root should have at least one focusable child element,

14

* for setting initial focus when trapping focus.

15

* Also tracks the previously focused element, and restores focus to that

16

* element when releasing focus.

17

*/

18

class FocusTrap {

19

constructor(root: HTMLElement, options?: FocusOptions);

20

trapFocus(): void;

21

releaseFocus(): void;

22

}

23

```

24

25

### Constructor

26

27

Create a new FocusTrap instance for a root element.

28

29

```typescript { .api }

30

/**

31

* Creates a new FocusTrap instance

32

* @param root - The root element to trap focus within

33

* @param options - Configuration options for focus behavior

34

*/

35

constructor(root: HTMLElement, options?: FocusOptions);

36

```

37

38

### Trap Focus

39

40

Activate focus trapping within the root element.

41

42

```typescript { .api }

43

/**

44

* Traps focus in root. Also focuses on either initialFocusEl if set;

45

* otherwise sets initial focus to the first focusable child element.

46

* @throws Error if the root element has no focusable children

47

*/

48

trapFocus(): void;

49

```

50

51

### Release Focus

52

53

Deactivate focus trapping and restore previous focus.

54

55

```typescript { .api }

56

/**

57

* Releases focus from root. Also restores focus to the previously focused

58

* element.

59

*/

60

releaseFocus(): void;

61

```

62

63

## Configuration Options

64

65

```typescript { .api }

66

interface FocusOptions {

67

/**

68

* The element to focus initially when trapping focus.

69

* Must be a child of the root element.

70

*/

71

initialFocusEl?: HTMLElement;

72

73

/**

74

* Whether to skip initially focusing on any element when trapping focus.

75

* By default, focus is set on the first focusable child element of the root.

76

* This is useful if the caller wants to handle setting initial focus.

77

*/

78

skipInitialFocus?: boolean;

79

80

/**

81

* Whether to restore focus on the previously focused element when releasing

82

* focus. This is useful if the caller wants to handle restoring focus.

83

*/

84

skipRestoreFocus?: boolean;

85

}

86

```

87

88

## Usage Examples

89

90

### Basic Modal Dialog

91

92

```typescript

93

import { FocusTrap } from '@material/dom/focus-trap';

94

95

// Create modal dialog

96

const dialog = document.querySelector('.dialog');

97

const focusTrap = new FocusTrap(dialog);

98

99

// Show modal and trap focus

100

dialog.classList.add('open');

101

focusTrap.trapFocus();

102

103

// Close modal and restore focus

104

function closeDialog() {

105

focusTrap.releaseFocus();

106

dialog.classList.remove('open');

107

}

108

```

109

110

### Modal with Custom Initial Focus

111

112

```typescript

113

import { FocusTrap } from '@material/dom/focus-trap';

114

115

const modal = document.querySelector('.modal');

116

const primaryButton = modal.querySelector('.primary-button');

117

118

const focusTrap = new FocusTrap(modal, {

119

initialFocusEl: primaryButton

120

});

121

122

// Show modal - focus will go to primary button

123

modal.style.display = 'block';

124

focusTrap.trapFocus();

125

```

126

127

### Skip Automatic Focus Management

128

129

```typescript

130

import { FocusTrap } from '@material/dom/focus-trap';

131

132

const drawer = document.querySelector('.drawer');

133

const focusTrap = new FocusTrap(drawer, {

134

skipInitialFocus: true, // Handle initial focus manually

135

skipRestoreFocus: true // Handle focus restoration manually

136

});

137

138

// Show drawer

139

drawer.classList.add('open');

140

focusTrap.trapFocus();

141

142

// Manually set focus

143

drawer.querySelector('.first-item').focus();

144

145

// Close drawer

146

focusTrap.releaseFocus();

147

drawer.classList.remove('open');

148

149

// Manually restore focus

150

document.querySelector('.menu-button').focus();

151

```

152

153

## Accessibility Features

154

155

### Focusable Element Detection

156

157

FocusTrap automatically detects focusable elements including:

158

- Elements with `tabindex` attribute

159

- Elements with `autofocus` attribute

160

- Interactive elements: `a`, `input`, `textarea`, `select`, `button`

161

- Elements that are visible and not disabled

162

- Elements not marked as `aria-hidden="true"`

163

164

### Sentinel Elements

165

166

The focus trap uses hidden "sentinel" elements to detect when focus attempts to leave the trapped area:

167

- Sentinels are placed at the beginning and end of the trapped region

168

- When a sentinel receives focus, it redirects to the appropriate boundary

169

- Sentinels are marked with `aria-hidden="true"` for screen readers

170

171

### Screen Reader Support

172

173

- Maintains proper focus order for screen reader navigation

174

- Doesn't interfere with screen reader virtual cursor

175

- Properly handles `aria-hidden` and `aria-disabled` attributes

176

- Works with assistive technology focus management

177

178

### Keyboard Navigation

179

180

- Supports Tab and Shift+Tab navigation

181

- Wraps focus from last to first element and vice versa

182

- Respects custom tab order via `tabindex` values

183

- Handles complex focusable element hierarchies

184

185

## Error Handling

186

187

```typescript

188

// FocusTrap will throw an error if root has no focusable children

189

const emptyDiv = document.createElement('div');

190

const focusTrap = new FocusTrap(emptyDiv);

191

192

try {

193

focusTrap.trapFocus();

194

} catch (error) {

195

console.error('FocusTrap: Element must have at least one focusable child.');

196

}

197

```