Transition to Core

This article digs into the syntax differences translation Express and Core apps as well as a translation guide to help you move from Express to Core.

The quickest way to tell whether an app is an Express app is the presence of shiny.express in the import statements. Common Express imports like from shiny.express import ui, input highlight the main difference from Core: expression of user interfaces (ui) and where input values come from. You’ll also commonly see Core imports like from shiny import reactive in Express apps, highlighting the fact that things like reactivity work the same way in both modes.

To dig into more specifics, consider the following app that just displays a slider value, and notice the following:

#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 150

from shiny import App, render, ui

app_ui = ui.page_fixed(
    ui.input_slider("val", "Slider label", min=0, max=100, value=50),
    ui.output_text_verbatim("slider_val")
)

def server(input, output, session):
    @render.text
    def slider_val():
        return f"Slider value: {input.val()}"

app = App(app_ui, server)
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 150

from shiny.express import input, render, ui

ui.input_slider("val", "Slider label", min=0, max=100, value=50)

@render.text
def slider_val():
    return f"Slider value: {input.val()}"

Now, suppose we add a UI component that takes other components as children, like ui.layout_columns(). In Core, this is done by nesting pure function calls. However, in Express, UI components that take other UI components as children are context managers, so we use with statements instead.

#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 150

from shiny import App, render, ui

app_ui = ui.page_fixed(
    ui.layout_columns(
      ui.input_slider("val", "Slider label", min=0, max=100, value=50),
      ui.output_text_verbatim("slider_val")
    )
)

def server(input, output, session):
    @render.text
    def slider_val():
        return f"Slider value: {input.val()}"

app = App(app_ui, server)
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 150

from shiny.express import input, render, ui

with ui.layout_columns():
    ui.input_slider("val", "Slider label", min=0, max=100, value=50)

    @render.text
    def slider_val():
        return f"Slider value: {input.val()}"
Terminal UI

Terminal UI components (e.g. ui.input_slider()); that is, components that usually don’t take other UI components as children, are not context managers in Express.

HTML tags

In Express, HTML tags can be used as both context managers and/or pure functions. For example, ui.div(ui.h1("Hello world!")) is also equivalent to with ui.div(): ui.h1("Hello world!").

Translation guide

When translating an Express app to Core, the following steps are recommended:

  1. Replace Express imports with Core imports (e.g., from shiny.express import ui -> from shiny import ui).
  2. Add from shiny import App.
  3. Add the following just below the imports:
app_ui = ui.page_fixed(
    # static UI here
)

def server(input, output, session):
    # render/reactive logic here
    ...

app = App(app_ui, server)
  1. Then, start moving the “top-level” Express logic into the UI/server:
  • Identify @render and @reactive functions and move them inside server function.
  • Add ui.output_*() containers to app_ui for each @render function.
  • Move ui components (i.e., inputs and layout) and move them inside the app_ui.
    • Remember that, in Core, layout components like ui.layout_columns() are pure functions, not context managers.
  • If your Express app has top-level ui.sidebar() and/or ui.nav_panel() components, you’ll need to also change ui.page_fixed() to ui.page_sidebar()/ui.page_navbar().

Footnotes

  1. In Express, page layout options can be controlled via ui.page_opts() and (at least some, for now) output containers can be controlled through their respective @render.*() decorators.↩︎