or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

focus-control-hooks.mdfocus-lock-components.mdindex.mdtypescript-types.md

focus-control-hooks.mddocs/

0

# Focus Control Hooks

1

2

React hooks for programmatic focus management, providing fine-grained control over focus behavior within and outside of focus locks. These hooks enable advanced focus manipulation scenarios and focus state tracking.

3

4

## Capabilities

5

6

### useFocusScope Hook

7

8

Returns FocusControl over the current FocusLock. Can only be used within a FocusLock component.

9

10

```typescript { .api }

11

/**

12

* Returns FocusControl over the current FocusLock

13

* Can only be used within FocusLock component

14

* @returns FocusControl interface for managing focus

15

*/

16

function useFocusScope(): FocusControl;

17

18

interface FocusControl {

19

/** Move focus to the current scope, acts as autofocus */

20

autoFocus(): Promise<void>;

21

22

/** Focus the next element in the scope */

23

focusNext(options?: FocusOptions): Promise<void>;

24

25

/** Focus the previous element in the scope */

26

focusPrev(options?: FocusOptions): Promise<void>;

27

28

/** Focus the first element in the scope */

29

focusFirst(options?: Pick<FocusOptions, 'onlyTabbable'>): Promise<void>;

30

31

/** Focus the last element in the scope */

32

focusLast(options?: Pick<FocusOptions, 'onlyTabbable'>): Promise<void>;

33

}

34

35

interface FocusOptions {

36

/** Enable focus cycle, default: true */

37

cycle?: boolean;

38

39

/** Limit to tabbable elements only, default: true */

40

onlyTabbable?: boolean;

41

}

42

```

43

44

**Usage Example:**

45

46

```typescript

47

import React from "react";

48

import FocusLock, { useFocusScope } from "react-focus-lock";

49

50

function NavigableModal() {

51

const focusScope = useFocusScope();

52

53

const handleKeyDown = async (event: React.KeyboardEvent) => {

54

switch (event.key) {

55

case 'ArrowDown':

56

event.preventDefault();

57

await focusScope.focusNext();

58

break;

59

case 'ArrowUp':

60

event.preventDefault();

61

await focusScope.focusPrev();

62

break;

63

case 'Home':

64

event.preventDefault();

65

await focusScope.focusFirst();

66

break;

67

case 'End':

68

event.preventDefault();

69

await focusScope.focusLast();

70

break;

71

}

72

};

73

74

return (

75

<div onKeyDown={handleKeyDown}>

76

<input placeholder="First input" />

77

<button>Middle button</button>

78

<input placeholder="Last input" />

79

</div>

80

);

81

}

82

83

function App() {

84

return (

85

<FocusLock>

86

<NavigableModal />

87

</FocusLock>

88

);

89

}

90

```

91

92

### useFocusController Hook

93

94

Returns FocusControl over given elements. Can be used outside of FocusLock and accepts HTML elements or React refs.

95

96

```typescript { .api }

97

/**

98

* Returns FocusControl over given elements

99

* Can be used outside of FocusLock

100

* @param shards - HTML elements or React refs to control

101

* @returns FocusControl interface for managing focus

102

*/

103

function useFocusController<Elements extends HTMLElement = HTMLElement>(

104

...shards: ReadonlyArray<HTMLElement | { current: HTMLElement | null }>

105

): FocusControl;

106

```

107

108

**Usage Example:**

109

110

```typescript

111

import React, { useRef } from "react";

112

import { useFocusController } from "react-focus-lock";

113

114

function CustomFocusController() {

115

const firstRef = useRef<HTMLInputElement>(null);

116

const secondRef = useRef<HTMLButtonElement>(null);

117

const thirdRef = useRef<HTMLInputElement>(null);

118

119

const focusController = useFocusController(firstRef, secondRef, thirdRef);

120

121

const handleNext = async () => {

122

await focusController.focusNext();

123

};

124

125

const handlePrevious = async () => {

126

await focusController.focusPrev();

127

};

128

129

const handleAutoFocus = async () => {

130

await focusController.autoFocus();

131

};

132

133

return (

134

<div>

135

<input ref={firstRef} placeholder="First controlled element" />

136

<button ref={secondRef}>Second controlled element</button>

137

<input ref={thirdRef} placeholder="Third controlled element" />

138

139

<div>

140

<button onClick={handleAutoFocus}>Auto Focus</button>

141

<button onClick={handleNext}>Focus Next</button>

142

<button onClick={handlePrevious}>Focus Previous</button>

143

</div>

144

</div>

145

);

146

}

147

```

148

149

### useFocusState Hook

150

151

Returns focus state information for a given node, tracking whether the node or its children have focus.

152

153

```typescript { .api }

154

/**

155

* Returns focus state information for a given node

156

* @param callbacks - Optional focus/blur callbacks

157

* @returns Object with focus state and handlers

158

*/

159

function useFocusState<T extends Element>(callbacks?: FocusCallbacks): {

160

/** Whether currently focused or focus is inside */

161

active: boolean;

162

163

/** Focus state string indicating type of focus relationship */

164

state: string;

165

166

/** Focus handler to be passed to the node */

167

onFocus: FocusEventHandler<T>;

168

169

/** Reference to the node */

170

ref: RefObject<T>;

171

};

172

173

interface FocusCallbacks {

174

/** Called when focus enters the node */

175

onFocus(): void;

176

177

/** Called when focus leaves the node */

178

onBlur(): void;

179

}

180

```

181

182

**Usage Example:**

183

184

```typescript

185

import React from "react";

186

import { useFocusState } from "react-focus-lock";

187

188

function FocusTracker() {

189

const { active, state, ref, onFocus } = useFocusState<HTMLDivElement>({

190

onFocus: () => console.log("Focus entered"),

191

onBlur: () => console.log("Focus left")

192

});

193

194

return (

195

<div ref={ref} onFocus={onFocus} className={active ? "focused" : "not-focused"}>

196

<h3>Focus Status: {active ? "Focused" : "Not Focused"}</h3>

197

<p>Focus State: {state}</p>

198

<input placeholder="Input inside tracker" />

199

<button>Button inside tracker</button>

200

</div>

201

);

202

}

203

```

204

205

### useFocusInside Hook

206

207

Moves focus inside a given node reference.

208

209

```typescript { .api }

210

/**

211

* Moves focus inside a given node reference

212

* @param node - React ref pointing to the target node

213

*/

214

function useFocusInside(node: RefObject<HTMLElement>): void;

215

```

216

217

**Usage Example:**

218

219

```typescript

220

import React, { useRef, useEffect } from "react";

221

import { useFocusInside } from "react-focus-lock";

222

223

function AutoFocusContainer() {

224

const containerRef = useRef<HTMLDivElement>(null);

225

226

// This will move focus inside the container on mount

227

useFocusInside(containerRef);

228

229

return (

230

<div ref={containerRef}>

231

<h3>Focus will move here</h3>

232

<input placeholder="This might get focused" />

233

<button>Or this button</button>

234

</div>

235

);

236

}

237

238

function ConditionalFocus({ shouldFocus }: { shouldFocus: boolean }) {

239

const containerRef = useRef<HTMLDivElement>(null);

240

241

useEffect(() => {

242

if (shouldFocus && containerRef.current) {

243

// Manually trigger focus inside

244

useFocusInside(containerRef);

245

}

246

}, [shouldFocus]);

247

248

return (

249

<div ref={containerRef}>

250

<input placeholder="Conditional focus target" />

251

<button>Another target</button>

252

</div>

253

);

254

}

255

```