# Riddle me this: how would you build a menu component that closes automatically and why?

**URL:** <https://discuss.emberjs.com/t/riddle-me-this-how-would-you-build-a-menu-component-that-closes-automatically-and-why/16320>\
**Category:** General\
**Created:** [March 13, 2019, 5:32pm UTC](https://discuss.emberjs.com/t/riddle-me-this-how-would-you-build-a-menu-component-that-closes-automatically-and-why/16320 "2019-03-13T17:32:17Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![efx](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/efx/32/17920_2.png) [@efx](https://discuss.emberjs.com/u/efx)\
**Post date:** [March 13, 2019, 5:32pm UTC](https://discuss.emberjs.com/t/riddle-me-this-how-would-you-build-a-menu-component-that-closes-automatically-and-why/16320/1 "2019-03-13T17:32:17Z")

</div>

I have a [menu component](https://github.com/efx/menu-close/blob/master/app/templates/components/menu.hbs#L1-L8) that opens when you click. I need it to close whenever the user clicks on option or anywhere else on the page. How would you solve this problem and what are the reasons for your approach? I can think of a couple but few seem best. The sub points are critiques of each approach.

1. portal approach ([RFC 287](https://emberjs.github.io/rfcs/0287-promote-in-element-to-public-api.html), [ember-wormhole](https://github.com/yapplabs/ember-wormhole), [ember-elsewhere](https://github.com/ef4/ember-elsewhere/))

2. [click masking](https://github.com/efx/menu-close/compare/master...solve-in-element-click-masking?expand=1) based on the portal approach

3. global event registration / teardown by the [menu component](https://github.com/efx/menu-close/compare/solve-global-handlers?expand=1)

4. click handler service to manage `document.addEventListener` approach in #2.

5. a component in your `application.hbs` [that wraps everything plus a service](https://github.com/efx/menu-close/compare/solve-component-wrap-and-service?expand=1)

Feel free to open a PR with a `solve-your-idea` branch in that repo!

---

<div class="post-metadata">

**Author:** ![BigRubyPy](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/bigrubypy/32/16385_2.png) [@BigRubyPy](https://discuss.emberjs.com/u/BigRubyPy)\
**Post date:** [March 13, 2019, 6:34pm UTC](https://discuss.emberjs.com/t/riddle-me-this-how-would-you-build-a-menu-component-that-closes-automatically-and-why/16320/2 "2019-03-13T18:34:53Z")

</div>

I’ll defer Ember solutions to more experienced Ember devs here but a general question:

What solution brings the least amount of overhead to your project? A traditional event JS DOM listener, while an older solution, will probably create the least amount of headache in negotiating the rest of your files.  
Especially if only needing to be fired once.

Then again, if you need other requirements for that component elsewhere in the project not layed out here - perhaps that would be redundant within the scope of the Ember app?

Hope this helps at all.

Carlo(BigRubyPy)

---

<div class="post-metadata">

**Author:** ![dknutsen](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/dknutsen/32/16471_2.png) [@dknutsen](https://discuss.emberjs.com/u/dknutsen)\
**Post date:** [March 13, 2019, 6:42pm UTC](https://discuss.emberjs.com/t/riddle-me-this-how-would-you-build-a-menu-component-that-closes-automatically-and-why/16320/3 "2019-03-13T18:42:57Z")

</div>

I recently made a quicksearch type component which does something similar (but is based around an input and a list of options instead of a button and a list of options and just did this in my component:

```auto
  focusIn() {
    this.set('showResults', true);
  },

  focusOut(evt) {
    // if new focus target is not contained within this component, close the menu
    if(!this.element.contains(evt.relatedTarget)) {
      this.set('showResults', false);
    }
  },

```

No idea if this is a good approach or what you’re looking for, I just kinda threw it in because it worked for what I needed.

Also this only handles the case where it’s not clicking on an item though, for that I handle those explicitly with actions.

I’m also not sure how this appears from an accessibility perspective (probably not great) but I’d think that relying on focus instead of just click is better. 🤷‍♂️

---

<div class="post-metadata">

**Author:** ![lvegerano](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/lvegerano/32/13973_2.png) [@lvegerano](https://discuss.emberjs.com/u/lvegerano)\
**Post date:** [March 22, 2019, 2:51pm UTC](https://discuss.emberjs.com/t/riddle-me-this-how-would-you-build-a-menu-component-that-closes-automatically-and-why/16320/4 "2019-03-22T14:51:12Z")

</div>

I’ve use [Ember Observer](https://www.emberobserver.com/addons/ember-click-outside). I think it would work great for what you want.

---

<div class="post-metadata">

**Author:** ![sukima](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/sukima/32/5773_2.png) [@sukima](https://discuss.emberjs.com/u/sukima)\
**Post date:** [March 24, 2019, 5:37pm UTC](https://discuss.emberjs.com/t/riddle-me-this-how-would-you-build-a-menu-component-that-closes-automatically-and-why/16320/5 "2019-03-24T17:37:00Z")

</div>

I’ve done this before. The problem is that it can quickly become overwhelming. Per the [ember-basicdropdown docs](https://ember-basic-dropdown.com/docs/):

> there are two kinds of people. Those who think that dropdowns are an easy thing and those who have actually built one.

For that I would recommend using an addon such as [ember-basic-dropdown](https://ember-basic-dropdown.com/docs/) and save yourself the headache of reinventing the wheel.

That said the bas pattern I have used in cases where a clean and fantastic addon was not available (lord have mercy on your soul if this is the case) is to attach and detach a global event handler.

```js
import Component from ‘@ember/component’;

export default Component.extend({
  open() {
    this.set(‘isOpen’, true);
    this._clickHandler = (evt) => this.handleClickEvent(evt);
    document.addEventListener(‘click’, this._clickHandler, false);
  },

  close() {
    this.set(‘isOpen’, false);
    this.cleanup();
  },

  cleanup() {
    document.removeEventListener(‘click’, this._clickHandler, false);
    this._clickHandler = null;
  },

  willDestroyElement() {
    this._super(...arguments);
    this.cleanup();
  }
});

```

And then there is some gnarly CSS to make it work. I recomend just using the addon!

---

<div class="post-metadata">

**Author:** ![efx](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/efx/32/17920_2.png) [@efx](https://discuss.emberjs.com/u/efx)\
**Post date:** [March 26, 2019, 7:53pm UTC](https://discuss.emberjs.com/t/riddle-me-this-how-would-you-build-a-menu-component-that-closes-automatically-and-why/16320/6 "2019-03-26T19:53:25Z")

</div>

Thanks for the responses all!

> [@BigRubyPy](#):
>
> What solution brings the least amount of overhead to your project?

@BigRubyPy Great question to consider for any refactoring. For this use case, I’m optimizing for readability and expressiveness.

> [@dknutsen](#):
>
> I recently made a quicksearch type component which does something similar

@dknutsen Neat idea. I’ve been hammering on this for a while thinking _it must be a click handler_ but perhaps not.

@lvegerano @sukima I will check these addons out. Our application already has a few implementations, so perhaps one of these can solve the issue.

> [@sukima](#):
>
> ave yourself the headache of reinventing the wheel.

Agreed. Three cheers for shared conventions! Though mad-prototyping-development-life has spread the definition of this behavior across our app in at least 3 places. A little state here, a little mutablity there. _All good_

> [@sukima](#):
>
> And then there is some gnarly CSS to make it work

Oh yes. I’ve been learning how dreadful this is for large applications. _You mean there are styles affecting this component’s behavior?_

---

<div class="post-metadata">

**Author:** ![sheriffderek](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/sheriffderek/32/10619_2.png) [@sheriffderek](https://discuss.emberjs.com/u/sheriffderek)\
**Post date:** [April 3, 2019, 9:57pm UTC](https://discuss.emberjs.com/t/riddle-me-this-how-would-you-build-a-menu-component-that-closes-automatically-and-why/16320/7 "2019-04-03T21:57:19Z")

</div>

I don’t have a better solution… _but as a use-case_: we recently built [a little trivia game](http://bumblebeemovie.com/trivia). Because it was so small, I just created a ‘ui-state’ service - and then anytime an answer was chosen (or any other type of non-menu button) was clicked (while the menu was open) - I set the `currentMenu` to null. It only ended up being 4 places (and not just clicking anywhere on the screen) - but I can see how that would get out of hand quickly. You have to think about scrolling / and resizing too. And what if there is a video playing or something that should also subscribe to menu UI type events. Yikes!

For fun: One _non-code_ solution is to build _a different interface_. Our visual-designer wanted this slide up and down type of thing (which was cool) - but as an example / I explained that if the menu was a full-screen take-over… we wouldn’t have to keep track of that state. You would either have the menu open _or_ you’d have to close it. And, it might not feel as fancy… but it sure changes the budget and the number of things to keep track of - if you’re trying to do something fast.

 ![54%20PM](https://us1.discourse-cdn.com/flex019/uploads/emberjs_public/original/3X/6/8/685e338f78982b73ef5c98095e5bcff32a812f4f.png)

I didn’t win on the menu - but I did put all the video type stuff in a modal / which really helped out for keeping track of state.

---

<div class="post-metadata">

**Author:** ![sukima](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/sukima/32/5773_2.png) [@sukima](https://discuss.emberjs.com/u/sukima)\
**Post date:** [April 5, 2019, 7:12pm UTC](https://discuss.emberjs.com/t/riddle-me-this-how-would-you-build-a-menu-component-that-closes-automatically-and-why/16320/8 "2019-04-05T19:12:41Z")

</div>

> [@sheriffderek](#):
>
> It only ended up being 4 places (and not just clicking anywhere on the screen) - but I can see how that would get out of hand quickly. You have to think about scrolling / and resizing too. And what if there is a video playing or something that should also subscribe to menu UI type events.

It would seem to me that the state management of these edge cases would be best suited to be handled in a service object which offers a clear API. This way those 4+ places simply call a method on the service instead of worry about clearing any state. You could also expose edge case APIs for dealing with videos etc. This way the clean up and choice to change the menu state is the responsibility of the service and not the 4+ call sites.

Or did I mis understand your application structure?

---

<div class="post-metadata">

**Author:** ![sheriffderek](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/sheriffderek/32/10619_2.png) [@sheriffderek](https://discuss.emberjs.com/u/sheriffderek)\
**Post date:** [April 9, 2019, 6:14am UTC](https://discuss.emberjs.com/t/riddle-me-this-how-would-you-build-a-menu-component-that-closes-automatically-and-why/16320/9 "2019-04-09T06:14:49Z")

</div>

I definitely used a service.

> Because it was so small, I just created a ‘ui-state’ service

: )
