I've created a mobile dropdown menu that toggles open and closed based on state. Once it's open, I would like the user to be able to close the dropdown by clicking anywhere outside the ul.
I'm setting the tabIndex attribute on the ul to 0, which gives the ul "focus". I've also added an onBlur event to the ul that triggers the state change (dropdownExpanded = false) that hides the ul.
<ul tabIndex="0" onBlur={this.hideDropdownMenu}>
<li onClick={this.handlePageNavigation}>Page 1</li>
<li onClick={this.handlePageNavigation}>Page 2</li>
<li onClick={this.handlePageNavigation}>Page 3</li>
</ul>
However, when I implement this fix, the onClick events that I have on each li element fail to fire.
I know something is going on with the event bubbling, but I am at a lose as to how to fix it. Can anyone help?
NOTE:
I know you can create a transparent div below the ul that spans the entire viewport and then just add an onClick even to that div that will change the state, but I read about this tabIndex/focus solution on Stack Overflow and I'd really like to get it working.
Here is a more complete view of the code (the dropdown is for users to select their home country, which updates the ui):
const mapStateToProps = (state) => {
return {
lang: state.lang
}
}
const mapDispatchToProps = (dispatch) => {
return { actions: bindActionCreators({ changeLang }, dispatch) };
}
class Header extends Component {
constructor() {
super();
this.state = {
langListExpanded: false
}
this.handleLangChange = this.handleLangChange.bind(this);
this.toggleLangMenu = this.toggleLangMenu.bind(this);
this.hideLangMenu = this.hideLangMenu.bind(this);
}
toggleLangMenu (){
this.setState({
langListExpanded: !this.state.langListExpanded
});
}
hideLangMenu (){
this.setState({
langListExpanded: false
});
}
handleLangChange(e) {
let newLang = e.target.attributes['0'].value;
let urlSegment = window.location.pathname.substr(7);
// blast it to shared state
this.props.actions.changeLang( newLang );
// update browser route to change locale, but stay where they are at
browserHistory.push(`/${ newLang }/${ urlSegment }`);
//close dropdown menu
this.hideLangMenu();
}
compileAvailableLocales() {
let locales = availableLangs;
let selectedLang = this.props.lang;
let markup = _.map(locales, (loc) => {
let readableName = language[ selectedLang ].navigation.locales[ loc ];
return (
<li
key={ loc }
value={ loc }
onMouseDown={ this.handleLangChange }>
{ readableName }
</li>
);
});
return markup;
}
render() {
let localeMarkup = this.compileAvailableLocales();
return (
<section className="header row expanded">
< Navigation />
<section className="locale_selection">
<button
className="btn-locale"
onClick={this.toggleLangMenu}>
{this.props.lang}
</button>
<ul
className={this.state.langListExpanded ? "mobile_open" : " "}
value={ this.props.lang }
tabIndex="0"
onBlur={this.hideLangMenu}>
>
{ localeMarkup }
</ul>
</section>
</section>
)
}
}