Popovers and action menus
Build a reusable task action panel
Reuse one popover across task cards and update its target context before the panel opens.
Just as one dialog can edit many tasks, one popover can serve the More actions button on every card. The important part is connecting the shared panel to the task whose invoker opened it.
A delegated click handler records the task ID before the browser toggles the popover. The action buttons then operate on that ID. The popover’s toggle event clears stale context when it closes, preventing a later keyboard or scripted action from touching the previous task.
const board = document.querySelector("#board")
const taskActions = document.querySelector("#task-actions")
let actionTaskId = null
board.addEventListener("click", event => {
const opener = event.target.closest("button[popovertarget=task-actions]")
if (opener) actionTaskId = opener.closest("[data-task-id]").dataset.taskId
})
taskActions.addEventListener("click", event => {
const action = event.target.closest("button[data-action]")?.dataset.action
if (action && actionTaskId) runTaskAction(actionTaskId, action)
taskActions.hidePopover()
})
taskActions.addEventListener("toggle", event => {
if (event.newState === "closed") actionTaskId = null
})
Give every More actions button a name that includes context when repeated controls would otherwise be indistinguishable. aria-label="More actions for Write homepage" is direct. The visible task heading also provides nearby context, but explicit names improve navigation through controls.
Keep focus predictable. Opening a simple popover does not automatically mean focus must jump into it. For a panel containing several actions, moving focus to its first button may be helpful; after an action or dismissal, return to the invoker if it still exists.
Do not close the panel before an action has captured the task ID. Calling hidePopover() produces state changes immediately enough that a cleanup handler may clear shared context. Pass the ID into the action function first, or copy it to a local constant.
Add the same popovertarget to three task cards, update each accessible label, and run Duplicate or Archive from the shared panel. Test opening with one card, dismissing, then opening from another. If the first task changes, inspect the exact order in which context is assigned, used, and cleared.
Lesson completed