reflex
reflex copied to clipboard
Scroll to section after click a link inside a drawer don't work
Describe the bug I created a sidebar menu using the drawer component. After clicking any link inside it, the menu closes, but the scroll to the section doesn't work.
To Reproduce
import reflex as rx
class DrawerState(rx.State):
is_open: bool = False
def toggle_drawer(self):
self.is_open = not self.is_open
def drawer_content():
return rx.drawer.content(
rx.flex(
rx.drawer.close(rx.button("Close", on_click=DrawerState.toggle_drawer)),
rx.link("Link 1", href="#test1", on_click=DrawerState.toggle_drawer),
rx.link("Link 2", href="#test2", on_click=DrawerState.toggle_drawer),
align_items="start",
direction="column",
),
top="auto",
right="auto",
height="100%",
width="100%",
padding="2em",
background_color="#FFF"
)
def lateral_menu():
return rx.drawer.root(
rx.drawer.trigger(rx.button("Open Drawer", on_click=DrawerState.toggle_drawer)),
rx.drawer.overlay(),
rx.drawer.portal(drawer_content()),
open=DrawerState.is_open,
direction="left",
)
def index():
return rx.vstack(
lateral_menu(),
rx.section(
rx.heading("Test1", size="8"),
id='test1',
height="900px",
),
rx.section(
rx.heading("Test2", size="8"),
id='test2',
height="900px",
)
)
app = rx.App()
app.add_page(index, route="/")
Expected behavior After clicking any link in the menu do scroll to the proper section
Specifics (please complete the following information):
- Python Version: 3.11.7
- Reflex Version: 0.4.2
- OS: Zorin OS (Ubuntu-based)
- Browser (Optional): Google Chrome
- Is there any other options better than a drawer for this purpose?
- I tried changing the drawer component parameters like preventScrollRestoration, and it doesn't work.
- Also, I tried to replicate the reflex-web sidebar menu. Curiously, after clicking any link that redirects to a different page, it works, although with a slight delay
Thank you in advance
Thanks for reporting this issue.
If you don't toggle the drawer closed on the links, does the page scroll to the anchor correctly?
Thanks for reporting this issue.
If you don't toggle the drawer closed on the links, does the page scroll to the anchor correctly?
No. Even by removing all the event callbacks, no scroll occurs by clicking the links. So,maybe it is a problem of the component itself
I played around with this today and it seems that the problem is the drawer itself wants to prevent scrolling of the page behind it by default (modal={true}
). It "releases" its scrolling lock on a couple of conditions:
https://github.com/emilkowalski/vaul/blob/c2588f0dc43552dde47b31516a254743d8eb87f5/src/index.tsx#L123-L125
Notably, isOpen
getting set to false should release the scroll lock... however isOpen
doesn't get set for 300ms after the open prop gets set to false, so there's this delay where the browser wants to scroll, but the drawer is still holding the scroll position (presumably to do it's drawer close animation)
https://github.com/emilkowalski/vaul/blob/c2588f0dc43552dde47b31516a254743d8eb87f5/src/index.tsx#L445-L453
which calls
https://github.com/emilkowalski/vaul/blob/c2588f0dc43552dde47b31516a254743d8eb87f5/src/index.tsx#L421-L424
The quick workaround here, is to set modal=False
in the rx.drawer.root
def lateral_menu():
return rx.drawer.root(
rx.drawer.trigger(rx.button("Open Drawer", on_click=DrawerState.toggle_drawer)),
rx.drawer.overlay(),
rx.drawer.portal(drawer_content()),
open=DrawerState.is_open,
direction="left",
modal=False,
)
If i do this, then your navigation links do work fine. The only downside to this approach is that while the drawer is open, the user can scroll the page behind the drawer. Whether this is a problem for you or not depends on your app.
I think it might be worth submitting an upstream bug or PR to vaul
itself, and see if they will instead link up the openProp
to their scroll prevention mechanism, which could allow the browser to beat the race, but no guarantee if this has the intended effect.
Thank you @masenf for working around this. Currently, this menu is only for mobile. I can use a non-modal option, but I hope there is a solution in future versions because this menu is quite common in different layouts. Sadly, I'm not an expert in JavaScript/typescript/react, so my contribution is to testing and reporting these problems.