sumi

Basics · Events

Bubbling and defaults

An element event is dispatched from the tree root down to the target, then handlers run from the deepest element upward — this is bubbling. When a button sits inside a clickable row, clicking the button runs the button’s handler and then the row’s. Here markDone and selectRow both fire, and because the row runs last it wins, so the status ends up saying the wrong thing.

evt.StopPropagation() stops the event before it reaches handlers higher up the path. Call it in the inner handler and the row never sees the click.

There is a second control, evt.PreventDefault(), which suppresses the built-in action that runs after dispatch — the runtime activating a focused button on Enter, typing a key into a focused input, moving focus on Tab. Those defaults are why the Done button already responds to Enter with no extra wiring: a focused button plus a click handler means Enter synthesises a click. PreventDefault cancels whichever default would apply.

Your turn

Make the Done button own its click. Give markDone the event and stop the click bubbling to the row:

func markDone(evt *sumi.DOMEvent) {
    evt.StopPropagation()
    status.Set("Marked done")
}

Press Run and click Done — the status now stays on “Marked done” instead of being overwritten by the row.

⌘↵ to run