File tree Expand file tree Collapse file tree 5 files changed +138
-8
lines changed
packages/react-interactions/accessibility Expand file tree Collapse file tree 5 files changed +138
-8
lines changed Original file line number Diff line number Diff line change
1
+ # FocusControl
2
+
3
+ ` FocusControl ` is a module that exports a selection of helpful utility functions to be used
4
+ in conjunction with the ` ref ` from a React Scope, such as ` TabbableScope ` .
5
+ A ref from ` FocusManager ` can also be used instead.
6
+
7
+ ## Example
8
+
9
+ ``` jsx
10
+ const {
11
+ focusFirst ,
12
+ focusNext ,
13
+ focusPrevious ,
14
+ getNextScope ,
15
+ getPreviousScope ,
16
+ } = FocusControl;
17
+
18
+ function KeyboardFocusMover (props ) {
19
+ const scopeRef = useRef (null );
20
+
21
+ useEffect (() => {
22
+ const scope = scopeRef .current ;
23
+
24
+ if (scope) {
25
+ // Focus the first tabbable DOM node in my children
26
+ focusFirst (scope);
27
+ // Then focus the next chilkd
28
+ focusNext (scope);
29
+ }
30
+ });
31
+
32
+ return (
33
+ < TabbableScope ref= {scopeRef}>
34
+ {props .children }
35
+ < / TabbableScope>
36
+ );
37
+ }
38
+ ```
39
+
40
+ ## FocusControl API
41
+
42
+ ### ` focusFirst `
43
+
44
+ Focus the first node that matches the given scope.
45
+
46
+ ### ` focusNext `
47
+
48
+ Focus the next sequential node that matchs the given scope.
49
+
50
+ ### ` focusPrevious `
51
+
52
+ Focus the previous sequential node that matchs the given scope.
53
+
54
+ ### ` getNextScope `
55
+
56
+ Focus the first node that matches the next sibling scope from the given scope.
57
+
58
+ ### ` getPreviousScope `
59
+
60
+ Focus the first node that matches the previous sibling scope from the given scope.
Original file line number Diff line number Diff line change
1
+ # FocusManager
2
+
3
+ ` FocusManager ` is a component that is designed to provide basic focus management
4
+ control. These are the various props that ` FocusManager ` accepts:
5
+
6
+ ## Usage
7
+
8
+ ``` jsx
9
+ function MyDialog (props ) {
10
+ return (
11
+ < FocusManager containFocus= {true } autoFocus= {true }>
12
+ < div>
13
+ < h2> {props .title }< h2>
14
+ < p> {props .text }< / p>
15
+ < Button onPress= {... }> Accept< / Button>
16
+ < Button onPress= {... }> Close< / Button>
17
+ < / div>
18
+ < / FocusManager>
19
+ )
20
+ }
21
+ ```
22
+
23
+ ### ` scope `
24
+ ` FocusManager ` accepts a custom ` ReactScope ` . If a custom one is not supplied, ` FocusManager `
25
+ will default to using ` TabbableScope ` .
26
+
27
+ ### ` autoFocus `
28
+ When enabled, the first host node that matches the ` FocusManager ` scope will be focused
29
+ upon the ` FocusManager ` mounting.
30
+
31
+ ### ` restoreFocus `
32
+ When enabled, the previous host node that was focused as ` FocusManager ` is mounted,
33
+ has its focus restored upon ` FocusManager ` unmounting.
34
+
35
+ ### ` containFocus `
36
+ This contains the user focus to only that of ` FocusManager ` s sub-tree. Tabbing or
37
+ interacting with nodes outside the sub-tree will restore focus back into the ` FocusManager ` .
38
+ This is useful for modals, dialogs, dropdowns and other UI elements that require
39
+ a form of user-focus control that is similar to the ` inert ` property on the web.
Original file line number Diff line number Diff line change
1
+ # TabbableScope
2
+
3
+ ` TabbableScope ` is a custom scope implementation that can be used with
4
+ ` FocusManager ` , ` FocusList ` , ` FocusTable ` and ` FocusControl ` modules.
5
+
6
+ ## Usage
7
+
8
+ ``` jsx
9
+ function FocusableNodeCollector (props ) {
10
+ const scopeRef = useRef (null );
11
+
12
+ useEffect (() => {
13
+ const scope = scopeRef .current ;
14
+
15
+ if (scope) {
16
+ const tabFocusableNodes = scope .getScopedNodes ();
17
+ if (tabFocusableNodes && props .onFocusableNodes ) {
18
+ props .onFocusableNodes (tabFocusableNodes);
19
+ }
20
+ }
21
+ });
22
+
23
+ return (
24
+ < TabbableScope ref= {scopeRef}>
25
+ {props .children }
26
+ < / TabbableScope>
27
+ );
28
+ }
29
+ ```
30
+
31
+ ## Implementation
32
+
33
+ ` TabbableScope ` uses the experimental ` React.unstable_createScope ` API. The query
34
+ function used for the scope is designed to collect DOM nodes that are tab focusable
35
+ to the browser. See the [ implementation] ( ../src/TabbableScope.js#L12-L33 ) here.
Original file line number Diff line number Diff line change @@ -110,7 +110,7 @@ export function focusPrevious(
110
110
}
111
111
}
112
112
113
- export function getNextController (
113
+ export function getNextScope (
114
114
scope : ReactScopeMethods ,
115
115
) : null | ReactScopeMethods {
116
116
const allScopes = scope . getChildrenFromRoot ( ) ;
@@ -124,7 +124,7 @@ export function getNextController(
124
124
return allScopes [ currentScopeIndex + 1 ] ;
125
125
}
126
126
127
- export function getPreviousController (
127
+ export function getPreviousScope (
128
128
scope : ReactScopeMethods ,
129
129
) : null | ReactScopeMethods {
130
130
const allScopes = scope . getChildrenFromRoot ( ) ;
Original file line number Diff line number Diff line change @@ -301,16 +301,12 @@ describe('FocusManager', () => {
301
301
FocusControl . focusPrevious ( firstFocusController ) ;
302
302
expect ( document . activeElement ) . toBe ( buttonRef . current ) ;
303
303
304
- const nextController = FocusControl . getNextController (
305
- firstFocusController ,
306
- ) ;
304
+ const nextController = FocusControl . getNextScope ( firstFocusController ) ;
307
305
expect ( nextController ) . toBe ( secondFocusController ) ;
308
306
FocusControl . focusFirst ( nextController ) ;
309
307
expect ( document . activeElement ) . toBe ( divRef . current ) ;
310
308
311
- const previousController = FocusControl . getPreviousController (
312
- nextController ,
313
- ) ;
309
+ const previousController = FocusControl . getPreviousScope ( nextController ) ;
314
310
expect ( previousController ) . toBe ( firstFocusController ) ;
315
311
FocusControl . focusFirst ( previousController ) ;
316
312
expect ( document . activeElement ) . toBe ( buttonRef . current ) ;
You can’t perform that action at this time.
0 commit comments