<div class="wrapper">
        <div class="left">

            <div class="block" id="block-1">
                <div class="block" id="block-2">
                    <div class="block" id="block-3">
                        <div class="block" id="block-4">
                            <div class="block" id="block-5">
                                <div class="block" id="block-6">
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>

        </div>

        <form class="right" id="settings-form">
            <div class="settings">
                <div>
                    Dispatch on:
                    <div>
                        <input type="radio" name="target" id="target-block-1" value="block-1">
                        <label for="target-block-1">#block-1</label>
                    </div>
                    <div>
                        <input type="radio" name="target" id="target-block-2" value="block-2a">
                        <label for="target-block-2">#block-2</label>
                    </div>
                    <div>
                        <input type="radio" name="target" id="target-block-3" value="block-3">
                        <label for="target-block-3">#block-3</label>
                    </div>
                    <div>
                        <input type="radio" name="target" id="target-block-4" value="block-4">
                        <label for="target-block-4">#block-4</label>
                    </div>
                    <div>
                        <input type="radio" name="target" id="target-block-5" value="block-5" checked>
                        <label for="target-block-5">#block-5</label>
                    </div>
                    <div>
                        <input type="radio" name="target" id="target-block-6" value="block-6">
                        <label for="target-block-6">#block-6</label>
                    </div>

                    <div>&nbsp;<hr ></div>
                    <div>
                        <input type="checkbox" name="bubbles" id="bubbles" value="true" checked>
                        <label for="bubbles">Bubbles</label>
                    </div>
                </div>

                <div>
                    Capture on:
                    <div>
                        <input type="checkbox" name="capture" id="capture-block-1" value="block-1" checked>
                        <label for="capture-block-1">#block-1</label>
                    </div>
                    <div>
                        <input type="checkbox" name="capture" id="capture-block-2" value="block-2" checked>
                        <label for="capture-block-2">#block-2</label>
                    </div>
                    <div>
                        <input type="checkbox" name="capture" id="capture-block-3" value="block-3" checked>
                        <label for="capture-block-3">#block-3</label>
                    </div>
                    <div>
                        <input type="checkbox" name="capture" id="capture-block-4" value="block-4" checked>
                        <label for="capture-block-4">#block-4</label>
                    </div>
                    <div>
                        <input type="checkbox" name="capture" id="capture-block-5" value="block-5" checked>
                        <label for="capture-block-5">#block-5</label>
                    </div>
                    <div>
                        <input type="checkbox" name="capture" id="capture-block-6" value="block-6" checked>
                        <label for="capture-block-6">#block-6</label>
                    </div>
                </div>

                <div>
                    Stop propagation on:
                    <div>
                        <input type="radio" name="stopPropagation" id="stopPropagation-block-1" value="block-1">
                        <label for="stopPropagation-block-1">#block-1</label>
                    </div>
                    <div>
                        <input type="radio" name="stopPropagation" id="stopPropagation-block-2" value="block-2">
                        <label for="stopPropagation-block-2">#block-2</label>
                    </div>
                    <div>
                        <input type="radio" name="stopPropagation" id="stopPropagation-block-3" value="block-3">
                        <label for="stopPropagation-block-3">#block-3</label>
                    </div>
                    <div>
                        <input type="radio" name="stopPropagation" id="stopPropagation-block-4" value="block-4">
                        <label for="stopPropagation-block-4">#block-4</label>
                    </div>
                    <div>
                        <input type="radio" name="stopPropagation" id="stopPropagation-block-5" value="block-5">
                        <label for="stopPropagation-block-5">#block-5</label>
                    </div>
                    <div>
                        <input type="radio" name="stopPropagation" id="stopPropagation-block-6" value="block-6">
                        <label for="stopPropagation-block-6">#block-6</label>
                    </div>
                    <div>
                        <input type="radio" name="stopPropagation" id="stopPropagation-none" value="none" checked>
                        <label for="stopPropagation-none">none</label>
                    </div>
                </div>
            </div>

            <div class="actions">
                <button type="submit">Dispatch event</button>
                <button id="reset">Reset</button>
            </div>

            <div class="legend">
                <div class="legend-item">
                    <div class="legend-rect"></div>
                    NONE
                </div>

                <div class="legend-item capture">
                    <div class="legend-rect"></div>
                    CAPTURING_PHASE
                </div>

                <div class="legend-item target">
                    <div class="legend-rect"></div>
                    AT_TARGET
                </div>

                <div class="legend-item bubble">
                    <div class="legend-rect"></div>
                    BUBBLING_PHASE
                </div>
            </div>
        </form>
    </div>
.wrapper {
          display: flex;
          justify-content: space-between;
        }

        .left, .right {
          flex: 1 1 auto;
        }

        .settings {
          display: flex;
          gap: 20px;
        }

        .actions {
          display: flex;
          gap: 20px;
          margin-top: 50px;
        }

        .block {
          position: relative;
          padding: 10px 0 10px 20px;
          color: #555;

          &::before {
            content: '<div class="block">';
          }

          &::after {
            content: '</div>';
            display: block;
          }
        }

        .legend {
          margin-top: 50px;
        }

        .legend-item {
          display: flex;
          align-items: center;
          gap: 20px;
          margin-bottom: 10px;
          color: #555;
        }

        .legend-rect {
          width: 40px;
          height: 15px;
          border: 2px solid #555;
          background: rgba(150, 150, 150, 0.5);
        }

        .legend-item.target .legend-rect {
          border-color: rgb(200, 0, 0);
          background-color: rgba(200, 0, 0, 0.3);
        }

        .legend-item.capture .legend-rect {
          border-color: rgb(0, 150, 0);
          background-color: rgba(0, 150, 0, 0.3);
        }

        .legend-item.bubble .legend-rect {
          border-color: rgb(0, 0, 200);
          background-color: rgba(0, 0, 200, 0.3);
        }

        .target {
          color: rgb(200, 0, 0);
        }

        .capture {
          color: rgb(0, 150, 0);
        }

        .bubble {
          color: rgb(0, 0, 200);
        }

        .num {
          position: absolute;
          top: 10px;
          left: 5px;
        }

        #block-1 {
          &::before {
            content: '<div id="block-1">';
          }
        }

        #block-2 {
          &::before {
            content: '<div id="block-2">';
          }
        }

        #block-3 {
          &::before {
            content: '<div id="block-3">';
          }
        }

        #block-4 {
          &::before {
            content: '<div id="block-4">';
          }
        }

        #block-5 {
          &::before {
            content: '<div id="block-5">';
          }
        }

        #block-6 {
          &::before {
            content: '<div id="block-6">';
          }
        }
const PHASES = [
  "NONE",
  "CAPTURING_PHASE",
  "AT_TARGET",
  "BUBBLING_PHASE",
]

const blocks = [
  document.getElementById("block-1"),
  document.getElementById("block-2"),
  document.getElementById("block-3"),
  document.getElementById("block-4"),
  document.getElementById("block-5"),
  document.getElementById("block-6"),
];

let count = 0;

let target;
let bubble;
let capture;
let stopPropagation;

const form = document.getElementById("settings-form");

form.addEventListener("submit", (event) => {
  event.preventDefault();
  const settings = new FormData(event.target);

  target = settings.get("target");
  bubbles = !!settings.get("bubbles");
  capture = settings.getAll("capture");
  stopPropagation = settings.get("stopPropagation");

  reset();

  blocks.forEach((block) => {
    block.addEventListener("test", callback, { capture: capture.includes(block.getAttribute("id")) });
  });

  document.getElementById(target).dispatchEvent(new Event("test", { bubbles }));
});

document.getElementById("reset").addEventListener("click", (event) => {
  event.preventDefault();

  reset();

  form.querySelectorAll("[name='target']").forEach((element) => {
    element.checked = element.value === "block-5";
  });

  form.querySelector("[name='bubbles']").checked = true;

  form.querySelectorAll("[name='capture']").forEach((element) => {
    element.checked = true;
  });

  form.querySelectorAll("[name='stopPropagation']").forEach((element) => {
    element.checked = element.value === "none";
  });
})

function reset() {
  count = 0;

  document.querySelectorAll(".num").forEach((num) => {
    num.remove();
  });

  blocks.forEach(block => {
    block.removeEventListener("test", callback, { capture: true });
    block.removeEventListener("test", callback, { capture: false });
    block.classList.remove("target", "capture", "bubble");
  })
}

function callback(event) {
  const target = event.currentTarget;
  const phase = PHASES[event.eventPhase];
  const shouldStop = stopPropagation.includes(target.getAttribute("id"));
  const cnt = count;

  if (shouldStop) {
    event.stopPropagation();
  }

  setTimeout(() => {
    switch (phase) {
      case "AT_TARGET":
        target.classList.add("target");
        break;
      case "CAPTURING_PHASE":
        target.classList.add("capture");
        break;
      case "BUBBLING_PHASE":
        target.classList.add("bubble");
        break;
    }

    const num = document.createElement("div");
    num.classList = "num";
    num.innerHTML = cnt + 1;

    target.appendChild(num);

  }, ++count * 1000);
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.