File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -14,6 +14,7 @@ import {
1414} from './types' ;
1515import { createSearchClient , groupBy , noop } from './utils' ;
1616import { createStoredSearches } from './stored-searches' ;
17+ import { useTrapFocus } from './useTrapFocus' ;
1718import { Hit } from './Hit' ;
1819import { SearchBox } from './SearchBox' ;
1920import { ScreenState } from './ScreenState' ;
@@ -50,6 +51,7 @@ export function DocSearch({
5051 suggestions : [ ] ,
5152 } as any ) ;
5253
54+ const containerRef = React . useRef < HTMLDivElement | null > ( null ) ;
5355 const searchBoxRef = React . useRef < HTMLDivElement | null > ( null ) ;
5456 const dropdownRef = React . useRef < HTMLDivElement | null > ( null ) ;
5557 const inputRef = React . useRef < HTMLInputElement | null > ( null ) ;
@@ -63,6 +65,8 @@ export function DocSearch({
6365 : ''
6466 ) . current ;
6567
68+ useTrapFocus ( { container : containerRef . current } ) ;
69+
6670 const searchClient = React . useMemo ( ( ) => createSearchClient ( appId , apiKey ) , [
6771 appId ,
6872 apiKey ,
@@ -320,6 +324,7 @@ export function DocSearch({
320324
321325 return (
322326 < div
327+ ref = { containerRef }
323328 className = { [
324329 'DocSearch-Container' ,
325330 state . status === 'stalled' && 'DocSearch-Container--Stalled' ,
Original file line number Diff line number Diff line change 1+ import React from 'react' ;
2+
3+ interface UseTrapFocusProps {
4+ container : HTMLElement | null ;
5+ }
6+
7+ export function useTrapFocus ( { container } : UseTrapFocusProps ) {
8+ React . useEffect ( ( ) => {
9+ if ( ! container ) {
10+ return undefined ;
11+ }
12+
13+ const focusableElements = container . querySelectorAll < HTMLElement > (
14+ 'a[href]:not([disabled]), button:not([disabled]), input:not([disabled])'
15+ ) ;
16+ const firstElement = focusableElements [ 0 ] ;
17+ const lastElement = focusableElements [ focusableElements . length - 1 ] ;
18+
19+ function trapFocus ( event : KeyboardEvent ) {
20+ if ( event . key !== 'Tab' ) {
21+ return ;
22+ }
23+
24+ if ( event . shiftKey ) {
25+ if ( document . activeElement === firstElement ) {
26+ event . preventDefault ( ) ;
27+ lastElement . focus ( ) ;
28+ }
29+ } else if ( document . activeElement === lastElement ) {
30+ event . preventDefault ( ) ;
31+ firstElement . focus ( ) ;
32+ }
33+ }
34+
35+ container . addEventListener ( 'keydown' , trapFocus ) ;
36+
37+ return ( ) => {
38+ container . removeEventListener ( 'keydown' , trapFocus ) ;
39+ } ;
40+ } , [ container ] ) ;
41+ }
You can’t perform that action at this time.
0 commit comments