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);