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:...