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:
- Core requires an
App()
object, which in turn requires a UI definition and server function. - Core UI starts with a
ui.page_*()
call to create a page layout. It also requires output containers (i.e.,ui.output_*()
) in the UI with ids that match the correspondingrender
function.- In Express, these page and output containers are implicit.1
#| 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 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.
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:
- Replace Express imports with Core imports (e.g.,
from shiny.express import ui
->from shiny import ui
). - Add
from shiny import App
. - Add the following just below the imports:
= ui.page_fixed(
app_ui # static UI here
)
def server(input, output, session):
# render/reactive logic here
...
= App(app_ui, server) app
- Then, start moving the “top-level” Express logic into the UI/server:
- Identify
@render
and@reactive
functions and move them insideserver
function. - Add
ui.output_*()
containers toapp_ui
for each@render
function. - Move
ui
components (i.e., inputs and layout) and move them inside theapp_ui
.- Remember that, in Core, layout components like
ui.layout_columns()
are pure functions, not context managers.
- Remember that, in Core, layout components like
- If your Express app has top-level
ui.sidebar()
and/orui.nav_panel()
components, you’ll need to also changeui.page_fixed()
toui.page_sidebar()
/ui.page_navbar()
.
Footnotes
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.↩︎