Skip to content

Instantly share code, notes, and snippets.

@souporserious
Last active November 13, 2019 05:19
Show Gist options
  • Save souporserious/64f89e499a19b19a9160ede63172ef4e to your computer and use it in GitHub Desktop.
Save souporserious/64f89e499a19b19a9160ede63172ef4e to your computer and use it in GitHub Desktop.
Manage multiple React elements as if they were in one focus group.
import React, { Component, createContext } from 'react'
const SetRefContext = createContext()
function isOutsideElement({ source, target }) {
return source !== target && !source.contains(target)
}
class FocusGroup extends Component {
static defaultProps = {
onBlur: () => null,
}
static contextType = SetRefContext
nodes = {}
setRef = id => node => {
if (this.context) {
this.context(id)(node)
}
if (node) {
this.nodes[id] = node
} else {
delete this.nodes[id]
}
}
requestBlur = event => {
const nextFocusedElement = event.relatedTarget || document.activeElement
if (
Object.keys(this.nodes).every(key =>
isOutsideElement({
source: this.nodes[key],
target: nextFocusedElement,
})
)
) {
this.props.onBlur(event)
}
}
render() {
return (
<SetRefContext.Provider value={this.setRef}>
{this.props.children({
setRef: this.setRef,
requestBlur: this.requestBlur,
})}
</SetRefContext.Provider>
)
}
}
export default FocusGroup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment