Vue

HTML

<div id="app">
  <parent></parent>
</div>

SCSS

html, body {
  height: 100%;
  width: 100%;
}

body {
  background: #20262E;
  font-family: Helvetica;
}

*, *::before, *::after {
  box-sizing: border-box;
}

#app {
  background: #fff;
  padding: 20px;
  height: 100%;
}

.m-dropdown {
  width: 100%;
}

.m-item-selector__item-wrapper {
  border: 1px solid black;
  width: 100%;
  text-align: left;
}

.m-dropdown__button,
.m-item-selector__item {
  position: relative;
  width: 100%;
  cursor: pointer;
  border: 0;
  text-transform: uppercase;
  text-align: left;
}

.m-item-selector__item {
  padding: 10px;
}

.m-dropdown__button {
  position: relative;
  border: 1px solid black;
  background-color: rgba(0,0,0,0.2);
  padding: 0;
    
  &::after {
    content: '⬇️';
    position: absolute;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    display: block;
    width: 20px;
    height: 20px;
  }
}

Vue

// Child component.
const ChildTemplate = `
	<div class="m-dropdown">
    <button
      class="m-dropdown__button"
      aria-haspopup="true"
      aria-expanded="false"
      @click="handleClick"
      @keyup.esc="close"
      @closeDropdown="isActive = false"
    >
      <slot name="dropdownToggle"></slot>
    </button>
    <div
      class="m-dropdown__content"
      v-show="isActive"
    >
      <slot name="dropdownContent"></slot>
    </div>
  </div>
`;

const Child = {
    template: ChildTemplate,
    data() {
      return {
        isActive: false,
        dropdownCTA: null,
        dropdownCTAClassname: 'm-dropdown__button',
      };
    },
    methods: {
      handleClick(e) {
        this.isActive = !this.isActive;
        this.dropdownCTA = e.target.closest('button');
        this.dropdownCTA.setAttribute('aria-expanded', 'true');
      },
      close() {
        if (this.isActive) {
          this.isActive = false;
          this.dropdownCTA.setAttribute('aria-expanded', 'false');
        }
      },
      documentClick(e) {
        const el = this.$el;
        if (this.isActive && el !== e.target && !el.contains(e.target)) {
          this.close();
        }
      },
    },
    created() {
      document.addEventListener('click', this.documentClick);
    },
    destroyed() {
      document.removeEventListener('click', this.documentClick);
    }   
};

// Parent component.
const ParentTemplate = `
	<child class="m-item-selector">
    <div
      class="m-item-selector__item"
      slot="dropdownToggle"
    >
       {{itemSelected}} 
    </div>
    <ul
      slot="dropdownContent"
      class="m-item-selector__item-list"
    >
      <li
        class="m-item-selector__item-wrapper"
        v-for="(item, index) in items"
        :key="index"
      >
        <button
        	class="m-item-selector__item"
          @click="selectItem(item)"
         >
         	{{item}}
         </button>
      </li>
    </ul>
  </child>
`;

const Parent = {
    template:...