widgetti / solara

A Pure Python, React-style Framework for Scaling Your Jupyter and Web Apps
https://solara.dev
MIT License
1.65k stars 114 forks source link

Feature Request: Programmatically focus on a component #640

Open JovanVeljanoski opened 3 weeks ago

JovanVeljanoski commented 3 weeks ago

It would be nice to make available the functionality to focus on a component (say a text input component) after interacting with another component (i.e. a button).

An example of this would be something like:

I saw that this is possible via the .focus() method in ipyvuetify, but that is not exposed in solara. There is a kwarg that makes a certain input text field be in focus when the app starts, but that is lost once the user interacts with other components (buttons, sliders etc..).

maartenbreddels commented 3 weeks ago

Hi Jovan,

good question, I'd like to see this in action before I can answer this fully, lets call next week and you can demo this to us ok?

I think there is one argument we can expose, which is the autofocus property, that is available in inputs in vuetify (it's an HTML feature). But I'd like @mariobuikhuizen 's input on this since he wasn't a big fan of programmatically focus, so I wonder what he thinks of this.

This seemed to work nicely:

import solara

show_dialog = solara.reactive(False)

@solara.component
def Page():
    solara.InputText("No focus")
    solara.InputText("Focus", autofocus=True)
    solara.InputText("No focus")
    solara.Button("Show dialog", on_click=lambda: show_dialog.set(True))

    with solara.v.Dialog(v_model=show_dialog.value, on_v_model=show_dialog.set, persistent=True, max_width="500px"):
        with solara.v.Sheet(class_="pa-4"):
            solara.InputText("No focus")
            solara.InputText("Focus", autofocus=True)
            solara.InputText("No focus")
            solara.Button("Close", on_click=lambda: show_dialog.set(False))

But it would require this patch:

diff --git a/solara/components/input.py b/solara/components/input.py
index 0332d709..31b7fc79 100644
--- a/solara/components/input.py
+++ b/solara/components/input.py
@@ -47,6 +47,7 @@ def InputText(
     update_events: List[str] = ["blur", "keyup.enter"],
     error: Union[bool, str] = False,
     message: Optional[str] = None,
+    autofocus: bool = False,
     classes: List[str] = [],
     style: Optional[Union[str, Dict[str, str]]] = None,
 ):
@@ -131,6 +132,7 @@ def InputText(
         type="password" if password else None,
         error=bool(error),
         messages=messages,
+        autofocus=autofocus,
         class_=classes_flat,
         style_=style_flat,
     )

Regards,

Maarten

JovanVeljanoski commented 2 weeks ago

Hi!

Thanks for the help! I don't think this works for my case tho (i tried it before). What this thing does (i think) it focuses the element in question on the page load, but after that it does not re-focus..

I think that's why ipyvuetify component has the .focus() method, that works (but without the reactivity of course)

Edit: I do get the focus correctly on pageload with your suggestion above. But interacting with buttons etc.. it is lost immediately. Also if the element is disabled (and pushing a button enables it) the focus is also lost.