<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>GOAT group</title>
  <style>
  </style>
</head>
<body>
  <h1>Who's the GREATEST GROUP OF ALL TIME?!</h1>
  <input id="group-sub-input"/>
  <button id="group-sub-btn">Submit</button>
  <goat-group guess="">🤔</goat-group>
</body>
</html>
body {
      font-family: monospace; /* notice how the font crosses the shadow DOM boundary*/
}
h1 {
  color: green;
}
// light DOM stuff
const groupSubmitInput = document.querySelector('#group-sub-input');
const groupSubmitBtn = document.querySelector('#group-sub-btn');
const goatGroupEl = document.querySelector('goat-group');
groupSubmitBtn.addEventListener('click', () => {
  console.log('button clicked!', groupSubmitInput.value);
  goatGroupEl.setAttribute('guess', groupSubmitInput.value);
  groupSubmitInput.value = '';
})

// Listen for the Custom Event dispatched from the Web Component
window.addEventListener('guessed', (e)=>{
  alert(e.detail);
})

// Create the template element
const template = document.createElement('template');
template.innerHTML = `
<slot></slot>
<h1></h1> 
<div id='verdict'></div>
`

//HTMLElement is the base class that powers other native elements like <input>, <button>, <video> etc.
class GoatGroup extends HTMLElement {
  // which attributes do we want to listen for changes
  static get observedAttributes() { return ['guess']; };
  constructor() {
    super(); // get all the HTMLElement goodness (methods and properties)
    // clone the Template so we can use it.
    const clone = document.importNode(template.content, true);
    // using Shadow DOM
    this.attachShadow({ mode: 'open' }); // should the shadow root's internal features be accessible via JavaScript? open or closed.
    this.shadowRoot.appendChild(clone);
    //  
    this.addEventListener('click', () => {
      this.style.color = 'red';
    });
  }
  
  // lifecycle callback invoked each time your custom element is appended to the DOM. Can be called multiple times.
  connectedCallback() {
    console.log('goat group connected!');
    this.style.color = 'blue';
  }
  
  // called when an attribute has been changed.
  attributeChangedCallback(name, oldValue, newValue) {
    console.log('attribute changed!: ', name, newValue);
    if (newValue.trim() === ''){
      this.shadowRoot.querySelector('#verdict').innerText = "";
    } else if (newValue.toLowerCase() === 'outkast'){
      this.shadowRoot.querySelector('h1').innerText = `${newValue.toUpperCase()}!!!!`;
      this.shadowRoot.querySelector('#verdict').innerText = "You're RIGHT!!";
      this.dispatchEvent(new CustomEvent('guessed', {
        detail: 'yup',
        bubbles: true, //bubble up through the component
        composed: true //allows event to cross into light DOM
      }));
    } else {
      this.shadowRoot.querySelector('h1').innerText = `${newValue}?!`;
      this.shadowRoot.querySelector('#verdict').innerText = "They're okay, I guess.";
      this.dispatchEvent(new CustomEvent('guessed', {
        detail: 'nope',
        bubbles: true, //bubble up through the component
        composed: true //allows event to cross into light DOM
      }));
    }
  }
    
  // called when your custom element is disconnected from the page. Useful to remove event listeners, intervals etc to prevent memory leaks
  disconnectedCallback() {
    console.log('goat group disconnected!');    
  }  
}

// connects our custom element to our class.
customElements.define('goat-group', GoatGroup);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.