Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!-- the same example as previously, this time with Shadow DOM -->
<my-element nickname="Ada">
  <div>Lovelace</div> <!-- unless you define a slot in the Shadow DOM, this content will not be displayed -->
</my-element>
<p><button id="show-message">Show message</button><p>
<form id="change-attr">
  <input name="newname" type="text" placeholder="New name">
  <button>Change by attribute</button>
</form>
<form id="change-prop">
  <input name="newname" type="text" placeholder="New name">
  <button>Change by property</button>
</form>
<!-- some global styling for our element -->
<style>
  my-element {
    /*
      a CSS variable (defined in the custom element) being overridden
    */
    --name-border-style: brown;
  }
</style>
<template id="my-template">
  <!-- Shadow DOM styles are included in the template -->
  <style>
    /*
      :host refers to our custom element itself
      these styles can always be overridden using styles
      in the main document
    */
    :host {
      display: block;
      border: 1px solid red;
      padding: 5px;
    }
    h2 {
      /*
        here we define a CSS variable, along with a default value.
        the border will take this default colour unless overriden (as it is above)
      */
      border: 1px solid var(--name-border-style, blue);
      padding: 5px;
    }
    h3 {
      /*
        no CSS variables here, so this cannot be styled from
        outside the Shadow DOM
      */
      border: 1px solid green;
      padding: 5px;
    }
    /*
      the ::slotted selector allows you to style the contents of you custom
      element tag (the light DOM) - but any rules here will be overriden by global rules
    */
    ::slotted(div) {
      border: 1px solid orange;
      padding: 5px;
    }
  </style>
  <h1>My First Custom Element</h1>
  <h2 id="nickname"></h2>
  <!--
    any content inside the my-element tag (known as the light DOM) will be shown in place
    of <slot>
  -->
  <h3><slot></slot></h3>
</template>
<script>
class MyElement extends HTMLElement {
  set nickname(val) {
    this.setAttribute('nickname', val);
  }
  get nickname() {
    return this.getAttribute('nickname');
  }
  showMessage() {
    alert('Hi ' + this.nickname);
  }
  
  static get observedAttributes() {
    return ['nickname'];
  }
  constructor() {
    super();
    const template = document.getElementById('my-template');
    const instance = template.content.cloneNode(true);
    /*
      create a Shadow DOM and attach it to this element
    */
    this.attachShadow({mode: 'open'});
    /*
      append our template instance into the Shadow DOM
    */
    this.shadowRoot.appendChild(instance);
  }
  attributeChangedCallback(name, oldValue, newValue) {
    /*
      now we query the Shadow DOM, rather than the element directly
    */
    this.shadowRoot.querySelector('#nickname').textContent = newValue;
  }
}
customElements.define('my-element', MyElement);
const myelement = document.querySelector('my-element');
const messageButton = document.querySelector('#show-message');
messageButton.addEventListener('click', () => {
   myelement.showMessage();
});
  
const formAttr = document.querySelector('#change-attr');
formAttr.addEventListener('submit', (event) => {
  event.preventDefault();
  myelement.setAttribute('nickname', event.target.newname.value);
});
const formProp = document.querySelector('#change-prop');
formProp.addEventListener('submit', (event) => {
  event.preventDefault();
  myelement.nickname = event.target.newname.value;
});
</script>
Output

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
lamplightdevpro
0viewers