class AccordionItem extends HTMLElement { static get observedAttributes() { return ['title']; } #title = ''; #collapsed = true; constructor() { super(); this.attachShadow({ mode: 'open' }); } connectedCallback() { this.update(); this.shadowRoot.addEventListener('click', this.toggle.bind(this)); } attributeChangedCallback(name, oldValue, newValue) { if (name === 'title') { this.#title = newValue; } this.update(); } toggle() { this.#collapsed = !this.#collapsed; this.update(); // Dispatch a custom event to notify the parent AccordionElement const event = new CustomEvent('accordion-item-toggle', { bubbles: true, detail: { collapsed: this.#collapsed, item: this, }, }); this.dispatchEvent(event); } update() { this.shadowRoot.innerHTML = `
${this.#title}
`; } } class AccordionElement extends HTMLElement { #activeItem = null; constructor() { super(); this.attachShadow({ mode: 'open' }); this.shadowRoot.innerHTML = ''; this.addEventListener('accordion-item-toggle', this.handleItemToggle.bind(this)); } handleItemToggle(event) { const { collapsed, item } = event.detail; // If the active item is different from the toggled item, collapse the active item if (this.#activeItem && this.#activeItem !== item && !collapsed) { this.#activeItem.toggle(); } // Update the active item if (!collapsed) { this.#activeItem = item; } else if (this.#activeItem === item) { this.#activeItem = null; } } } customElements.define('accordion-item', AccordionItem); customElements.define('accordion-element', AccordionElement);