reflex icon indicating copy to clipboard operation
reflex copied to clipboard

Scroll to section after click a link inside a drawer don't work

Open Valdes-Tresanco-MS opened this issue 5 months ago β€’ 4 comments

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

Valdes-Tresanco-MS avatar Mar 07 '24 05:03 Valdes-Tresanco-MS

Thanks for reporting this issue.

If you don't toggle the drawer closed on the links, does the page scroll to the anchor correctly?

masenf avatar Mar 07 '24 06:03 masenf

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

Valdes-Tresanco-MS avatar Mar 07 '24 07:03 Valdes-Tresanco-MS

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.

masenf avatar Mar 07 '24 20:03 masenf

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.

Valdes-Tresanco-MS avatar Mar 07 '24 22:03 Valdes-Tresanco-MS