← Back to Home

Example 2: Counter Component

A stateful Web Component with event handling

Live Demo

Try clicking the buttons below. The counter maintains its own state!

JavaScript Code

class CounterWidget extends HTMLElement {
  constructor() {
    super();
    this._count = 0;
  }
  
  connectedCallback() {
    // Get initial value from attribute
    this._count = parseInt(this.getAttribute('initial')) || 0;
    this.render();
    this.attachEventListeners();
  }
  
  increment() {
    this._count++;
    this.render();
    // Dispatch custom event
    this.dispatchEvent(new CustomEvent('countchange', {
      detail: { count: this._count }
    }));
  }
  
  decrement() {
    this._count--;
    this.render();
    this.dispatchEvent(new CustomEvent('countchange', {
      detail: { count: this._count }
    }));
  }
  
  reset() {
    this._count = 0;
    this.render();
  }
  
  render() {
    this.innerHTML = \`
      <div style="display: flex; align-items: center; gap: 10px; 
                  padding: 20px; background: #f5f0e8; border-radius: 0;
                  margin: 10px 0;">
        <button data-action="decrement" style="
          padding: 10px 20px; border: none; background: #2d1b69;
          color: white; border-radius: 0; cursor: pointer;
          font-size: 18px; font-weight: bold;">
          -
        </button>
        <span style="font-size: 32px; font-weight: bold; 
                     color: #2d1b69; min-width: 60px; text-align: center;">
          \${this._count}
        </span>
        <button data-action="increment" style="
          padding: 10px 20px; border: none; background: #2d1b69;
          color: white; border-radius: 0; cursor: pointer;
          font-size: 18px; font-weight: bold;">
          +
        </button>
        <button data-action="reset" style="
          padding: 10px 20px; border: none; background: #e8e3db;
          color: #1a1a1a; border-radius: 0; cursor: pointer;">
          Reset
        </button>
      </div>
    \`;
    
    // Re-attach event listeners after render
    this.attachEventListeners();
  }
  
  attachEventListeners() {
    const buttons = this.querySelectorAll('button');
    buttons.forEach(button => {
      button.addEventListener('click', (e) => {
        const action = e.target.getAttribute('data-action');
        if (action === 'increment') this.increment();
        if (action === 'decrement') this.decrement();
        if (action === 'reset') this.reset();
      });
    });
  }
}

customElements.define('counter-widget', CounterWidget);

Key Concepts

Listen to Events

Open the console to see events. Try this code:

document.querySelector('counter-widget').addEventListener('countchange', (e) => {
  console.log('Count changed to:', e.detail.count);
});

Documentation

Next Step