Regain focus after disabling input

I want to disable the input box while it is processing, and to re-enable and return the focus to it when processing is done

This works to disable and re-enable the input box but it loses the focus when disabled and does not get it back when re-enabled. How to return the focus to the point where the user stopped typing?

from dash import Dash, html, callback, Output, Input, dcc
from time import sleep

input_tag = dcc.Input(id='input', debounce=0.500, autoFocus=True)
output_tag = dcc.Input(id='output', disabled=True)

app = Dash(__name__,)
app.layout = [html.Div([input_tag, output_tag]),]

@callback(
   Output('output', 'value'),
   Input('input', 'value'),
   prevent_initial_call=True,
   running=[(Output('input', 'disabled'), True, False)]
)
def process(value: str):
   sleep(2)
   return value

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

Hello @clodoaldo,

You will need to leverage the clientside callback and use JS to reset the focus after the callback has run. You’ll need to use a dcc.Store or something to trigger it.

So I should just RTFM

Here the solution, including a spinner. The affected input attribute must be readonly instead of disabled:

from dash import Dash, html, callback, Output, Input, dcc
from time import sleep
import dash_bootstrap_components as dbc

input_tag = dbc.Input(id='input', debounce=500, autoFocus=True)
output_tag = dbc.Input(id='output', disabled=True)

app = Dash(__name__,)
app.layout = [
   html.Div([input_tag, dcc.Loading(
      children=html.Div(id='spinner_div'),type='circle',)]
      , style={'width': 'fit-content'}
   ),
   html.Div([output_tag]),
   ]

app.clientside_callback(
    """
    function(disabled) {
        if (disabled === false) {
            const el = document.getElementById('input');
            if (el) {
                el.focus();
            }
        }
        return window.dash_clientside.no_update;
    }
    """,
    Input('input', 'readonly')
)

@callback(
   Output('spinner_div', 'children'),
   Output('output', 'value'),
   Input('input', 'value'),
   prevent_initial_call=True,
   running=[(Output('input', 'readonly'), True, False)]
)
def process(value: str):
   sleep(1)
   return '', value

if __name__ == '__main__':
    app.run(debug=True)
1 Like