JSFiddle - React, Tailwind, and code Playground
by IvanBender
HTML
<div id="root"></div>
CSS
div {
position: relative;
display: flex;
flex-direction: column;
width: 300px;
height: 100px;
justify-content: space-between;
}
ul {
position: absolute;
top: 5px;
left: 50px;
width: 100px;
height: 80px;
background: #000;
border-radius: 5px;
}
li {
color: #fff;
}
Babel + JSX
class BlurExample extends React.Component {
constructor(props) {
super(props)
this.state = { isOpen: false }
this.timeOutId = null
this.onClickHandler = this.onClickHandler.bind(this)
this.onBlurHandler = this.onBlurHandler.bind(this)
this.onFocusHandler = this.onFocusHandler.bind(this)
}
onClickHandler() {
this.setState(currentState => ({
isOpen: !currentState.isOpen
}))
}
// Мы закрываем выпадающий список по таймеру setTimeout.
// Это нужно чтобы для дочерних элементов событие выделения
// происходило перед событием получения фокуса.
onBlurHandler() {
this.timeOutId = setTimeout(() => {
this.setState({
isOpen: false
})
})
}
// Не закрывать выпадающий список при получении фокуса дочерним элементом.
onFocusHandler() {
clearTimeout(this.timeOutId)
}
render() {
// React assists us by bubbling the blur and
// focus events to the parent.
return (
<>
<div onBlur={this.onBlurHandler} onFocus={this.onFocusHandler}>
<button onClick={this.onClickHandler} aria-haspopup="true" aria-expanded={this.state.isOpen}>
Select an option
</button>
{this.state.isOpen && (
<ul>
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
</ul>
)}
</div>
<button>Second</button>
<button>third</button>
</>
)
}
}
ReactDOM.render(
<BlurExample />,
document.getElementById('root')
);