zauberzeug / nicegui

Create web-based user interfaces with Python. The nice way.
https://nicegui.io
MIT License
10.11k stars 606 forks source link

`ui.log` scrolls to top when changing tabs #3852

Closed parlance-zz closed 1 month ago

parlance-zz commented 1 month ago

Description

Log elements lose their scroll position when changing tabs. This is a minor issue, but nonetheless it is mildly annoying and I think it is probably not the intended behavior. I've tried a few things but so far I've had no luck creating a workaround.

Minified reproduction code:

from nicegui import ui

def add_messages():
    for i in range(20):
        log.push(f"Message {i + 1}")

with ui.tabs() as tabs:
    button_tab = ui.tab("button")
    log_tab = ui.tab("log")

with ui.tab_panels(tabs, value=button_tab).classes("w-full"):
    with ui.tab_panel(button_tab):
        ui.button('Add 20 Messages', on_click=add_messages)
    with ui.tab_panel(log_tab):
        log = ui.log(max_lines=100)

ui.run()
falkoschindler commented 1 month ago

Thanks for reporting this issue, @parlance-zz!

Here is a reproduction without ui.log:

with ui.tabs() as tabs:
    tab1 = ui.tab('blank')
    tab2 = ui.tab('messages')

with ui.tab_panels(tabs):
    with ui.tab_panel(tab1):
        ui.label('Nothing to see here')
    with ui.tab_panel(tab2):
        with ui.column().classes('max-h-40'):
            for i in range(20):
                ui.label(f'Message {i + 1}')

It seems like this is normal Vue/Quasar behavior and we can't do much about it. Here's a reproduction without NiceGUI:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link href="https://cdn.jsdelivr.net/npm/quasar@2.17.0/dist/quasar.prod.css" rel="stylesheet" type="text/css" />
  </head>
  <body>
    <div id="q-app">
      <q-tabs v-model="tab">
        <q-tab name="blank" label="Blank"></q-tab>
        <q-tab name="messages" label="Messages"></q-tab>
      </q-tabs>
      <q-tab-panels v-model="tab" animated>
        <q-tab-panel name="blank">
          <div class="text-h6">Nothing to see here</div>
        </q-tab-panel>
        <q-tab-panel name="messages">
          <q-scroll-area style="height: 200px">
            <div v-for="i in 20" :key="i" class="q-py-xs">Message {{ i }}</div>
          </q-scroll-area>
        </q-tab-panel>
      </q-tab-panels>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@2.17.0/dist/quasar.umd.prod.js"></script>
    <script>
      const { ref } = Vue;
      const app = Vue.createApp({
        setup() {
          return { tab: ref("blank") };
        },
      });
      app.use(Quasar);
      app.mount("#q-app");
    </script>
  </body>
</html>

Therefore I'll have to close this issue as "won't fix".

parlance-zz commented 1 month ago

It seems like this is normal Vue/Quasar behavior and we can't do much about it.

Ah, I suspected as much - not a big deal!

Thank you for taking the time to look into it.

falkoschindler commented 1 month ago

Oh, there might be workaround - at least to always scroll to the bottom instead of jumping back to the top:

tabs.on_value_change(lambda: ui.run_javascript(f'getElement({log.id}).lastChild.scrollIntoView()'))

It slightly impacts the way the tab panel scrolls into view, because scrollIntoView() immediately shows the bottom of the log. But it might be a better UX nonetheless.

parlance-zz commented 1 month ago

Oh, there might be workaround - at least to always scroll to the bottom instead of jumping back to the top:

tabs.on_value_change(lambda: ui.run_javascript(f'getElement({log.id}).lastChild.scrollIntoView()'))

It slightly impacts the way the tab panel scrolls into view, because scrollIntoView() immediately shows the bottom of the log. But it might be a better UX nonetheless.

Beautiful! Exactly what I was looking for, many thanks again!