Skip to content

Instantly share code, notes, and snippets.

@forgo
Last active May 29, 2022 14:42
Show Gist options
  • Select an option

  • Save forgo/1e1070eb3515f3d253a37d05e64f4040 to your computer and use it in GitHub Desktop.

Select an option

Save forgo/1e1070eb3515f3d253a37d05e64f4040 to your computer and use it in GitHub Desktop.
Handle composite focus and blur events in React.
import React from 'react'
import ReactDOM from 'react-dom'
import { Key } from '../utils/keyboardUtils'
export default class FocusManager extends React.Component {
constructor(props) {
super(props)
this._immediateID = null
this.state = {
isManagingFocus: false,
}
}
componentDidMount() {
document.addEventListener('mousedown', this.handleMousedown);
}
componentWillUnmount() {
document.removeEventListener('mousedown', this.handleMousedown);
}
handleMousedown = event => {
const { onBlur } = this.props
const componentNode = ReactDOM.findDOMNode(this)
// only unset focus state and trigger overall blur event
// if mouse down event occurs outside of this component
if (!componentNode.contains(event.target)) {
this.setState({
isManagingFocus: false,
}, () => {
if (onBlur) {
onBlur(event)
}
})
}
}
handleKeyDown = event => {
const { onBlur } = this.props
if (event.keyCode === Key.ESCAPE) {
this.setState({
isManagingFocus: false,
}, () => {
if (onBlur) {
onBlur(event)
}
})
}
}
handleBlur = event => {
const { onBlur } = this.props
const { isManagingFocus } = this.state
this._immediateID = setImmediate(() => {
if (isManagingFocus) {
this.setState({
isManagingFocus: false,
}, () => {
if (onBlur) {
onBlur(event)
}
})
}
})
}
handleFocus = event => {
const { onFocus } = this.props
const { isManagingFocus } = this.state
clearImmediate(this._immediateID)
if (!isManagingFocus) {
this.setState({
isManagingFocus: true,
}, () => {
if (onFocus) {
onFocus(event)
}
})
}
}
render() {
return (
<div
role="focusManager"
onBlur={this.handleBlur}
onFocus={this.handleFocus}
onKeyDown={this.handleKeyDown}
>
{this.props.children}
</div>
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment