Filterable List Custum Element
by jacobwsmith
HTML
<h1>My Filterable List</h1>
<!-- Use the custom element -->
<filterable-list></filterable-list>
CSS
filterable-list {
display: block;
margin: 20px;
font-family: sans-serif;
}
.filter-input {
padding: 10px;
width: 100%;
box-sizing: border-box;
margin-bottom: 10px;
}
.list-items li {
padding: 8px;
border: 1px solid #ddd;
margin-top: -1px; /* Prevent double borders */
background-color: #f6f6f6;
}
.list-items li.hidden {
display: none;
}
JavaScript
class FilterableList extends HTMLElement {
constructor() {
super();
// Create a shadow root for encapsulation
this.attachShadow({ mode: 'open' });
this.itemsData = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape', 'Honeydew'];
}
connectedCallback() {
this.render();
this.shadowRoot.querySelector('.filter-input').addEventListener('keyup', this.filterList.bind(this));
}
render() {
this.shadowRoot.innerHTML = `
<style>
/* Scoped styles for the custom element */
.filter-input {
padding: 10px;
width: 100%;
box-sizing: border-box;
margin-bottom: 10px;
}
.list-items li {
padding: 8px;
border: 1px solid #ddd;
margin-top: -1px;
background-color: #f6f6f6;
}
.list-items li.hidden {
display: none;
}
</style>
<input type="text" class="filter-input" placeholder="Type to filter...">
<ul class="list-items">
${this.itemsData.map(item => `<li>${item}</li>`).join('')}
</ul>
`;
}
filterList(event) {
const query = event.target.value.toLowerCase();
const listItems = this.shadowRoot.querySelectorAll('.list-items li');
listItems.forEach(item => {
const text = item.textContent.toLowerCase();
if (text.includes(query)) {
item.classList.remove('hidden');
} else {
item.classList.add('hidden');
}
});
}
}
// Define the custom element
customElements.define('filterable-list', FilterableList);