Skip to content

Commit 7e98f2f

Browse files
Andrey Okonetchnikovokonet
authored andcommitted
docs(focus): Add docs and example for focus method
1 parent 3f271a0 commit 7e98f2f

File tree

2 files changed

+76
-43
lines changed

2 files changed

+76
-43
lines changed

src/FocusWithin.js

Lines changed: 50 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,33 @@
1-
import React from 'react'
2-
import PropTypes from 'prop-types'
1+
import React from "react";
2+
import PropTypes from "prop-types";
33

44
const noOutlineStyles = {
5-
outline: 'none'
6-
}
5+
outline: "none"
6+
};
77

88
class FocusWithin extends React.Component {
99
state = {
1010
focused: false
11-
}
11+
};
1212

13-
ref = React.createRef()
13+
ref = React.createRef();
1414

15-
/** @public
16-
* @function focus - calls `focus` method on the container node
17-
* @return void
15+
/**
16+
* Calls `focus` method on the container node
17+
*
18+
* @public
19+
* @method focus
1820
* */
1921
focus() {
20-
const node = this.ref.current
21-
if (node != null && typeof node.focus === 'function') {
22-
node.focus()
22+
const node = this.ref.current;
23+
if (node != null && typeof node.focus === "function") {
24+
node.focus();
2325
}
2426
}
2527

2628
onFocus = evt => {
27-
const { onFocus } = this.props
28-
const { focused } = this.state
29+
const { onFocus } = this.props;
30+
const { focused } = this.state;
2931

3032
// TODO: Figure out if this check is "safe" or we should rely on SCU instead
3133
if (!focused) {
@@ -34,61 +36,61 @@ class FocusWithin extends React.Component {
3436
focused: true
3537
},
3638
() => {
37-
onFocus(evt)
39+
onFocus(evt);
3840
}
39-
)
41+
);
4042
}
41-
}
43+
};
4244

4345
onBlur = evt => {
44-
const { onBlur } = this.props
45-
const { focused } = this.state
46+
const { onBlur } = this.props;
47+
const { focused } = this.state;
4648

4749
// Do not blur if focus within the container or we're editing
4850
if (this.isFocusWithin(this.ref.current)) {
49-
evt.preventDefault()
50-
evt.stopPropagation()
51-
return
51+
evt.preventDefault();
52+
evt.stopPropagation();
53+
return;
5254
}
5355

5456
// Persist event object
55-
evt.persist()
57+
evt.persist();
5658

5759
if (focused) {
5860
this.setState(
5961
{
6062
focused: false
6163
},
6264
() => {
63-
onBlur(evt)
65+
onBlur(evt);
6466
}
65-
)
67+
);
6668
}
67-
}
69+
};
6870

6971
isFocusWithin = node => {
7072
// We need to check `:focus-within` on the the parent element in order to work
71-
if (process.env.NODE_ENV === 'development') {
73+
if (process.env.NODE_ENV === "development") {
7274
if (
7375
node == null ||
7476
node.parentNode == null ||
75-
typeof node.parentNode.querySelector !== 'function'
77+
typeof node.parentNode.querySelector !== "function"
7678
) {
7779
throw new Error(
78-
'A ref to a DOM Node with a valid parent Node must be supplied to' +
79-
' FocusWithin.\n' +
80-
' You have probably provided a ref to a React Element.\n See https://reactjs.org/docs/react-api.html#refs'
81-
)
80+
"A ref to a DOM Node with a valid parent Node must be supplied to" +
81+
" FocusWithin.\n" +
82+
" You have probably provided a ref to a React Element.\n See https://reactjs.org/docs/react-api.html#refs"
83+
);
8284
}
8385
}
84-
return !!node.parentNode.querySelector(':focus-within')
85-
}
86+
return !!node.parentNode.querySelector(":focus-within");
87+
};
8688

8789
render() {
88-
const { children } = this.props
89-
const { focused } = this.state
90+
const { children } = this.props;
91+
const { focused } = this.state;
9092

91-
if (typeof children === 'function') {
93+
if (typeof children === "function") {
9294
return React.cloneElement(
9395
children({
9496
focused,
@@ -98,14 +100,19 @@ class FocusWithin extends React.Component {
98100
onFocus: this.onFocus,
99101
onBlur: this.onBlur
100102
}
101-
)
103+
);
102104
}
103105

104106
return (
105-
<div ref={this.ref} onFocus={this.onFocus} onBlur={this.onBlur} style={noOutlineStyles}>
107+
<div
108+
ref={this.ref}
109+
onFocus={this.onFocus}
110+
onBlur={this.onBlur}
111+
style={noOutlineStyles}
112+
>
106113
{children}
107114
</div>
108-
)
115+
);
109116
}
110117
}
111118

@@ -117,11 +124,11 @@ FocusWithin.propTypes = {
117124
children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired,
118125
onBlur: PropTypes.func,
119126
onFocus: PropTypes.func
120-
}
127+
};
121128

122129
FocusWithin.defaultProps = {
123130
onBlur: () => {},
124131
onFocus: () => {}
125-
}
132+
};
126133

127-
export default FocusWithin
134+
export default FocusWithin;

src/Readme.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,32 @@ const StyledBox = styled("div")`
9898

9999
_Note:_ It's recommended to use `:focus-within` selector instead of interpoaltions whenever possible.
100100

101+
## Focus method
102+
103+
Sometimes it's needed to focus the container node programmatically. You can use the public method
104+
`focus`. Note that `tabIndex={-1}` needs to be set on non-interactive elements to make them
105+
receive focus.
106+
107+
```jsx harmony
108+
const ref = React.createRef();
109+
<div>
110+
<FocusWithin ref={ref}>
111+
{({ focused, getRef }) => (
112+
<span tabIndex={-1} ref={getRef}>
113+
{focused ? "Focused" : "Not focused"}
114+
</span>
115+
)}
116+
</FocusWithin>
117+
<button
118+
onClick={() => {
119+
ref.current.focus();
120+
}}
121+
>
122+
Focus the span
123+
</button>
124+
</div>;
125+
```
126+
101127
## Naïve focus trap implementation
102128

103129
```jsx harmony

0 commit comments

Comments
 (0)