Overview
The term, user interface (UI), refers to the part of an application that is visible to the user. The UI is typically composed of a collection of components (e.g. buttons, sliders, plots, etc) that allow the user to interact with the application. Shiny provides roughly three types of UI components:
- Inputs: Components that gather user input (e.g. sliders, text boxes, etc).
- Outputs: Components that display the results (e.g. plots, tables, etc).
- Layouts: Components that arrange other components (e.g. columns, tabs, etc). Page layouts are a special type of layout that are used to start a new UI.
Inputs
Shiny provides a wide variety of input components, all of which:
- Start with
ui.input_*()
. - Require an
id
argument, alabel
, and sometimes other (mostly optional) arguments. - Allow their value to be read reactively using
input[id]()
. - Have a corresponding
ui.update_*()
function for efficiently updating the input control (see here for more details and examples).
Here’s a basic example of a text input (and printing its value to the console):
from shiny import reactive
from shiny.express import input, ui
"text", label="Enter some text")
ui.input_text(
@reactive.effect
def _():
print(input.text())
from shiny import App, reactive, ui
= ui.page_fluid(
app_ui "text", label="Enter some text")
ui.input_text(
)
def server(input):
@reactive.effect
def _():
print(input.text())
= App(app_ui, server) app
See this section of the component gallery for an overview of available inputs.
Some layout components, like ui.accordion()
or ui.navset_tab()
, take an optional id
argument. If provided, the id
can be used to read the selected tab/accordion panel reactively in the server using input[id]()
.
Outputs
Shiny provides a handful of output components, all of which:
- Require a (named) function decorated by a
@render.*
decorator. - Require the return value of the function to be a valid value (e.g. a string for
@render.text
, a plot for@render.plot
, etc).
Here’s a basic example of using a text output (reacting to changes in a text input):
from shiny.express import input, render, ui
"text", label="Enter some text")
ui.input_text(
@render.text
def text_out():
return f"Input text: {input.text()}"
from shiny import App, render, ui
= ui.page_fluid(
app_ui "text", label="Enter some text"),
ui.input_text("text_out")
ui.output_text(
)
def server(input):
@render.text
def text_out():
return f"Input text: {input.text()}"
= App(app_ui, server) app
In a Shiny core app, output components typically start with a ui.output_*()
object directly in the UI definition. Like inputs, outputs require an id
argument, which must match the name of the function that returns the output’s value in the server.
See this section of the component gallery for an overview of available outputs.
In the next article, Jupyter Widgets, you’ll learn how to use Jupyter Widgets as outputs.
Some outputs provide access their client-side state as input values. For example:
@render.plot
provides access to hover, click, and drag events.@render.data_frame
provides access to selected rows and more.{shinywidgets}
’s@render_widget()
provides access to the ipywidget traits.
Layouts
Layout components help with arrangement and styling of their child components. A handful of layout components start with ui.layout_*()
, but many other layout components are available as well (e.g. ui.card()
, ui.accordion()
, ui.navset_*()
functions, etc).
For a quick example, here’s how to arrange two sliders in a row:
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 100
from shiny.express import ui
with ui.layout_column_wrap(gap="2rem"):
ui.input_slider("slider1", "Slider 1", min=0, max=100, value=50)
ui.input_slider("slider2", "Slider 2", min=0, max=100, value=50)
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 100
from shiny import App, ui
app_ui = ui.page_fluid(
ui.layout_column_wrap(
ui.input_slider("slider1", "Slider 1", min=0, max=100, value=50),
ui.input_slider("slider2", "Slider 2", min=0, max=100, value=50),
gap="2rem"
)
)
app = App(app_ui, None)
See the layout gallery for an overview of available layout mechanisms.
Page layouts
A special type of layout is the page layout, which is used to start a new UI. In Shiny Express, the page layout is implicit, and automatically inferred from the top-level UI components. In Shiny Core, the page layout is explicit, meaning that the UI starts with a page layout component (e.g. ui.page_fluid()
, ui.page_sidebar()
, etc).
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 150
from shiny.express import ui
ui.page_opts(title="Page title")
with ui.sidebar():
"Sidebar content"
"Main content"
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 150
from shiny import App, ui
app_ui = ui.page_sidebar(
ui.sidebar("Sidebar content"),
"Main content",
title="Page title"
)
app = App(app_ui, None)
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 150
from shiny.express import ui
ui.page_opts(title="Page title")
with ui.nav_panel("Page 1"):
"Page 1 content"
with ui.nav_panel("Page 2"):
"Page 2 content"
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 150
from shiny import App, ui
app_ui = ui.page_navbar(
ui.nav_panel("Page 1", "Page 1 content"),
ui.nav_panel("Page 2", "Page 2 content"),
title="Page title"
)
app = App(app_ui, None)
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 150
from shiny.express import ui
ui.page_opts(fillable=True)
with ui.card():
"Card content"
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 150
from shiny import App, ui
app_ui = ui.page_fillable(
ui.card("Card content")
)
app = App(app_ui, None)
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 150
from shiny.express import ui
with ui.card():
"Card content"
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 150
from shiny import App, ui
app_ui = ui.page_fixed(
ui.card("Card content")
)
app = App(app_ui, None)
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 150
from shiny.express import ui
ui.page_opts(full_width=True)
with ui.card():
"Card content"
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 150
from shiny import App, ui
app_ui = ui.page_fluid(
ui.card("Card content")
)
app = App(app_ui, None)
Display messages
Another type of UI component is one used to display messages to the user (e.g. notifications, modals, tooltips, etc). Display messages like notifications and modals require server-side code to manage their state, so they are typically created in the server and then shown/hidden using the ui.*_show()
and ui.*_hide()
functions. Tooltips and popovers, on the other hand, can be created directly in the UI definition (i.e., statically rendered, without any server-side code).
See this section of the component gallery for an overview of available display messages.
Next steps
Next up, we’ll learn all about Shiny’s Jupyter Widgets integration.