Skip to content

table: no way to prevent row context menu when right-clicking header #2214

@boboshan

Description

@boboshan

Problem

When using TableDelegate::render_th() with ContextMenuExt to add context menus to column headers, right-clicking a header shows both the row context menu and the header context menu simultaneously.

Root cause

The row context menu is attached to inner_table (in render() at state.rs ~line 1973), which wraps both the header and body. When right-clicking a header cell:

  1. The inner_table context menu fires because the header is geometrically inside its bounds
  2. It reads right_clicked_row which may still be Some from a previous row click
  3. The header's own context menu (from ContextMenuExt) also opens independently
  4. Both menus appear at the same time

The on_mouse_down_out dismiss handler on the row menu doesn't fire because the click is inside inner_table's bounds.

Workaround

I overrode render_header to add on_mouse_down(MouseButton::Right) that clears the row state before menu builders run. However, right_clicked_row is private, so I forked and added:

pub fn clear_right_clicked_row(&mut self) {
    self.right_clicked_row = None;
}

Suggested fix

Either:

  1. Expose clear_right_clicked_row() (or a set_right_clicked_row) as a public method on TableState
  2. Add a header_context_menu() method to TableDelegate (similar to context_menu() for rows) that the framework handles correctly
  3. Window-level context menu tracking so opening any context menu auto-dismisses others

Option 1 is the smallest change. Option 2 is the cleanest API.

Reproduction

impl TableDelegate for MyDelegate {
    fn render_th(&mut self, col_ix: usize, _window: &mut Window, cx: &mut Context<TableState<Self>>) -> impl IntoElement {
        div()
            .id(("th", col_ix))
            .child("Header")
            .context_menu(|menu, _w, _cx| {
                menu.item(PopupMenuItem::new("Header action"))
            })
    }

    fn context_menu(&mut self, row_ix: usize, menu: PopupMenu, ...) -> PopupMenu {
        menu.item(PopupMenuItem::new("Row action"))
    }
}

Steps: Right-click a row → right-click a column header → two menus appear.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions