Recipe 12.3

Creating a Feedback Component

Demo

Code

JavaScript
const template = document.createElement('template');
template.innerHTML = `
  <style>
    .feedback-prompt {
      display: flex;
      align-items: center;
      gap: 0.5em;
    }

    button {
      padding: 0.5em 1em;
    }
  </style>

  <div class="feedback-prompt">
    <p>Was this helpful?</p>
    <button type="button" data-helpful="true">Yes</button>
    <button type="button" data-helpful="false">No</button>
  </div>
`;

class FeedbackRating extends HTMLElement {
  constructor() {
    super();

    // Create the shadow DOM and render the template into it
    const shadowRoot = this.attachShadow({ mode: 'open' });
    shadowRoot.appendChild(template.content.cloneNode(true));
  }

  connectedCallback() {
    this.shadowRoot.querySelector('.feedback-prompt').addEventListener('click', event => {
      const { helpful } = event.target.dataset;

      if (typeof helpful !== 'undefined') {
        // Once a feedback option is chosen, hide the buttons and show a confirmation
        this.shadowRoot.querySelector('.feedback-prompt').remove();
        this.shadowRoot.textContent = 'Thanks for your feedback!';

        // JavaScript doesn't have a 'parseBoolean' type function, so convert the string value
        // to the corresponding boolean value.
        this.helpful = helpful === 'true';

        // Dispatch a custom event, so your app can be notified when a feedback button
        // is clicked.
        this.shadowRoot.dispatchEvent(new CustomEvent('feedback', {
          composed: true, // this is needed to "escape" the shadow DOM boundary
          bubbles: true // this is needed to propagate up the DOM
        }));
      }
    });
  }
}

if (!customElements.get('feedback-rating')) {
  customElements.define('feedback-rating', FeedbackRating);
}

const feedback = document.querySelector('feedback-rating');
feedback.addEventListener('feedback', event => {
  const result = document.querySelector('#result');

  if (event.target.helpful ) {
    result.textContent = 'User indicated that the website was helpful.';
  } else {
    result.textContent = 'User indicated that the website was not helpful.';
  }
});
HTML
<style>
  button {
    background: pink !important;
  }
</style>

<feedback-rating></feedback-rating>

<div id="result"></div>
Web API Cookbook
Joe Attardi