Skip to content
Advertisement

Programmatically cause onBlur to trigger in react

I use onBlur to close a dropdown, but I also want to handle a click handler of an li which is render within, setState won’t work here, the behavior is broken when user try to open the dropdown again, try it here:

http://jsfiddle.net/ur1rbcrz

My code:

toggleDropdown = () => {
    this.setState({
        openDropdown: !this.state.openDropdown
    })
  }

  render() {
    return (
      <div>
        <div tabIndex="0" onFocus={this.toggleDropdown} onBlur={this.toggleDropdown}>
          MyList
        <ul className={this.state.openDropdown ? 'show' : 'hide'}>
          <li>abc</li>
          <li>123</li>
          <li onClick={()=> this.setState({openDropdown:false})}>xyz</li> {/* not working */}
        </ul>
      </div>
      </div>
    );
  }

Answer

Your code is not working because, even though you click li, a div container with onBlur event still is focused.

We add to your list container ref, after that we can call .blur(). We use it in your onClick li event handler.

this.dropDownList.blur()

See working example jsfiddle.

Or run this snippet:

class Hello extends React.Component {
  constructor() {
    super()
    this.state = {
      isDropdownVisible: false
    }
    
    this.toggleDropdown = this.toggleDropdown.bind(this);
  }
  
  toggleDropdown() {
  	this.setState({
    	isDropdownVisible: !this.state.isDropdownVisible
    })
  }
  
  render() {
    return (
      <div>
        <div 
        tabIndex="0" 
        ref={c => this.dropDownList = c}
        onFocus={this.toggleDropdown} 
        onBlur={this.toggleDropdown}>
          MyList
        <ul
        className={this.state.isDropdownVisible ? 'show' : 'hide'}>
          <li>abc</li>
          <li>123</li>
          <li onClick={() => this.dropDownList.blur()}>xyz</li> {/* not working */}
        </ul>
      </div>
      </div>
    );
  }
}

ReactDOM.render(
  <Hello initialName="World"/>,
  document.getElementById('container')
);
.hide {
  display: none
}

.show {
  display: block !important;
}

div:focus {
  border: 1px solid #000;
}

div:focus {
		outline: none;
	}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container">
  <!-- This element's contents will be replaced with your component. -->
</div>
Advertisement