Auto-focusing detail content after MasterDetailLayout opens via Grid row click

Context

Vaadin 25, Flow. I have a MasterDetailLayout where clicking a row in a Grid opens a detail panel via setDetail(). I want focus to move into the detail content so that:

  1. Pressing Escape closes the detail (via a Shortcuts.addShortcutListener(..., Key.ESCAPE).listenOn(wrapper))
  2. For form-based details, the first text field is ready to type in immediately

What I tried

I added an addAttachListener on the detail component that calls focus() when the component is attached:

For a read-only detail (non-focusable VerticalLayout wrapper):

wrapper.getElement().setAttribute("tabindex", "0");
Shortcuts.addShortcutListener(wrapper, onClose::run, Key.ESCAPE).listenOn(wrapper);
wrapper.addAttachListener(_ -> wrapper.getElement().callJsFunction("focus"));

For form-based details (VerticalLayout subclass with a TextField name as the first field):

Shortcuts.addShortcutListener(this, () -> fireEvent(new CancelEvent(this, false)), Key.ESCAPE)
        .listenOn(this);
addAttachListener(_ -> name.focus());

I also tried deferring with executeJs("setTimeout(() => this.focus(), 0)") instead of calling focus() / callJsFunction("focus") directly.

The problem

Focus is not reliably moved to the detail content. I can tell because after clicking a grid row and then pressing the arrow keys, the cursor is still navigating cells in the Grid — focus stayed in the grid.

My hypothesis: the Grid’s native click handler re-focuses the clicked cell after our server-round-trip completes and the addAttachListener fires. The setTimeout(..., 0) approach didn’t help either, suggesting the grid focus restoration happens later than a single tick.

Questions

  1. Is there a recommended pattern for moving focus out of a Grid into MasterDetailLayout detail content after a row selection opens the detail?
  2. Is there a Grid API to suppress its default focus management when a row is selected (e.g. an “activate row” action that opens the detail)?
  3. Should I be listening to a different event on the Grid — for example addItemClickListener instead of asSingleSelect().addValueChangeListener() — and is there any difference in focus behavior?
  4. Is there a MasterDetailLayout API or event I should use to set focus after the detail is shown?

Minimal reproduction

// Grid selection listener that opens detail
grid.asSingleSelect().addValueChangeListener(event -> {
    if (event.getValue() != null) {
        detailOpener.openDetail(buildDetail(event.getValue(), detailOpener::closeDetail));
    }
});

// Detail builder
static VerticalLayout buildDetail(MyItem item, Runnable onClose) {
    // ... build content ...
    VerticalLayout wrapper = new VerticalLayout(content);
    wrapper.setSizeFull();
    wrapper.getElement().setAttribute("tabindex", "0");

    Shortcuts.addShortcutListener(wrapper, onClose::run, Key.ESCAPE).listenOn(wrapper);
    wrapper.addAttachListener(_ -> wrapper.getElement().callJsFunction("focus"));

    return wrapper;
}

Any guidance appreciated. Thanks!

Imho it sounds more like a bug - detail should behave like a dialog that automatically gets focused. I would recommend to create an issue on GitHub (web-components) about it

1 Like

Focus only moves to the detail automatically when the layout is in overlay mode. When the layout is in split mode (i.e., both master and detail show side by side), focus stays in the master by default.

1 Like