nicegui-tabulator icon indicating copy to clipboard operation
nicegui-tabulator copied to clipboard

use_theme fails during app.on_startup: “current slot cannot be determined” (no slot/client context)

Open AlePiccin opened this issue 1 month ago • 2 comments

Summary Calling nicegui_tabulator.use_theme(...) inside a NiceGUI app.on_startup handler raises a RuntimeError: “The current slot cannot be determined because the slot stack for this task is empty.” This appears to happen because startup/background tasks run without an active UI slot/client context, yet use_theme accesses ui.context.client.

  • Minimal example:
    from nicegui import ui, app
    import nicegui_tabulator as tab

    @app.on_startup
    async def startup():
        tab.use_theme('site_dark', shared=True)

    @ui.page('/')
    def index():
        ui.label('Home')

    ui.run()
  • Start the app and observe the error during startup.

Expected Behavior

  • When called with shared=True, use_theme should be safe to call without an active client/slot (e.g., at startup) and apply a global/shared theme, or at least no-op gracefully until a client connects.

Actual Behavior

  • Raises at startup with:
    • RuntimeError: The current slot cannot be determined because the slot stack for this task is empty. This may happen if you try to create UI from a background task. To fix this, enter the target slot explicitly using with container_element:.
    • Trace shows use_theme → ui.context.client access, which requires a current slot.

Analysis

The case shared=None should translate to False.

Also,

    if ui.context.client.has_socket_connection:
        ui.run_javascript(
            """
    const linkElements = document.querySelectorAll('link.nicegui-tabulator-theme');
    linkElements.forEach(linkElement => {
        linkElement.parentNode.removeChild(linkElement);
    });
"""
        )

should be removed. It's the user responsability to call it before any table is created.

This would solve the problem.

AlePiccin avatar Nov 21 '25 19:11 AlePiccin

@AlePiccin, I don’t think we should just remove run_javascript outright. In dynamic theme switching scenarios, we need to ensure old-style links are removed.

Right now, it seems like we have a couple of options:

  1. Just check if the slot stack is not empty, and run run_javascript.
  2. Skip run_javascript entirely when shared=True.

What do you think?

CrystalWindSnake avatar Nov 25 '25 07:11 CrystalWindSnake

Hi @CrystalWindSnake. Thanks for the reply. I would go with the second approach. It fits both scenarios:

If the user wants to dynamically change the theme, they should use shared=False (and javascript will run to cleaning it all up).

If the user wants to set it globally, they should use shared=True (in preference inside @app.on_startup)

AlePiccin avatar Nov 25 '25 13:11 AlePiccin