dbc.Popover needs two callback firings to apply new target

I noticed that when one wants to change the target of a dbc.Popover, one needs to to it twice for some reason:

from dash import (Dash, html, dcc, callback)
from dash import Input, Output, State, ctx, no_update
import dash_bootstrap_components as dbc

app = Dash(__name__)

app.layout = html.Div([
    dbc.Button(id="button-1", children="I'm button 1"),
    dbc.Button(id="button-2", children="I'm button 2"),
    dbc.Button(id="button-3", children="I'm button 3"),
    dbc.Popover(id="popover", body=True, children="Some text", is_open=True, placement="bottom")
])


@callback(
    Output("popover", "target"),
    Input("button-1", "n_clicks"),
    Input("button-2", "n_clicks"),
    Input("button-3", "n_clicks"),
)
def change_popover_target(n1, n2, n3):
    if ctx.triggered_id == "button-1":
        return "button-1"
    elif ctx.triggered_id == "button-2":
        return "button-2"
    elif ctx.triggered_id == "button-3":
        return "button-3"
    return no_update


if __name__ == '__main__':
    app.run_server(debug=True)

That makes sense. The first click assigns the target component. At that point the Popover can be triggered on click, on hover or on focus (the default is on click). But those wont’ happen before the target component is specified.

But why does it need a second target assignment to change its position?

I’m not sure what you mean. When the app starts? If so, then change the return dash.no_update so that it has a default if no button is clicked. Or set a default in the layout.

When assigning a target in the layout, like target="button-1", I need to click button-2 two times to move the Popover to button 2. You explained why, I still think that this not intuitive.