Event Bubbling
HTML #
1<div id="demo">
2 Key pressed: <span data-text="$key"></span>
3 <div id="event-bubbling-container" data-on:click="$key = evt.target.closest('button[data-id]')?.dataset.id ?? $key">
4 <button data-id="KEY ELSE" class="gray">KEY<br/>ELSE</button>
5 <button data-id="CM">CM</button>
6 <button data-id="OM">OM</button>
7 <button data-id="FETCH">FETCH</button>
8 <button data-id="SET">SET</button>
9 <button data-id="EXEC">EXEC</button>
10 <button data-id="TEST ALARM" class="gray">TEST<br/>ALARM</button>
11 <button data-id="3">3</button>
12 <button data-id="2">2</button>
13 <button data-id="1">1</button>
14 <button data-id="ENTER">ENTER</button>
15 <button data-id="CLEAR">CLEAR</button>
16 </div>
17</div>
18
19<style>
20 #event-bubbling-container {
21 pointer-events: none;
22
23 button {
24 user-select: none;
25
26 * {
27 pointer-events: none;
28 user-select: none;
29 }
30 }
31 }
32</style>Explanation #
This example shows how event bubbling can be leveraged using Datastar. A data-on:click attribute on the parent container of the buttons. The listener is on the container, but evt.target can be a nested element inside a button, so we resolve the nearest matching button first with evt.target.closest('button[data-id]')?.dataset.id. This allows us to handle all button clicks with a single event listener.
Note the pointer-events: none; style on the button container to prevent container clicks, and pointer-events: none; on button contents (plus user-select: none;) so nested elements like <br> don’t become the click target.