shared_lifetime

shared_lifetime function

Construct one widget that every Shiny session displays.

Usage Source

shared_lifetime()

Experimental: not every widget package behaves well when one widget is mirrored into several browsers (see the caveats below), and this function’s behavior may change in a future release.

Widgets constructed inside this block exist once per Python process and are mirrored into the browser of every session that displays them: any user’s interaction with one changes it for everyone, and it is never freed. Use it for static content or state that is deliberately shared between users. To reuse a widget across renders within a single session instead, use session_lifetime().

A session is sent a shared widget the first time it displays it, or displays or updates a widget that references it (e.g., adds a shared layer to its own map), so a large shared widget costs nothing in the sessions that never show it. A shared widget that nothing a session displays references is never sent: create a jslink() between shared widgets per session (e.g., in the server function) rather than inside this block.

Works with or without an active session, so a widget can be built at module level and returned from any session’s render. Layout defaults a renderer applies to it (e.g., filling its container) affect it for all sessions. Output accessors (e.g., a plotly output’s clicked()) aren’t scoped to a session on a shared widget, so don’t rely on what they report there.

Construct each shared widget once: at the top level of a module the app imports, or lazily, cached in a module-level variable. Don’t construct one in code that runs per render or per session (including the body of a Shiny Express app file, which runs once per session): every widget built here is kept forever, so each run adds one more. Widgets a shared widget references (e.g., a container’s children) must be constructed inside shared_lifetime() too, or other sessions can’t show them.

Share widgets whose appearance is fully described by their state (their synced traits). A session that opens a shared widget receives its current state, not the messages it was sent before that session joined, so a widget that is drawn or changed by messages (e.g., an ipycanvas canvas’s drawing commands, or changes made to a Bokeh figure after its widget was created) looks incomplete to sessions that join later.

Don’t rely on models a shared widget’s JavaScript creates in the browser when a trait is left at its default (e.g., pythreejs’s light target and shadow): they belong to that one browser, and other sessions don’t have them. A session that opens the shared widget afterwards references a model it never received, waits 30 seconds for it (“Timeout waiting for widget model”), and the affected outputs never render. Give such traits explicit values, constructed inside shared_lifetime().