0
# Express Mode
1
2
Express mode provides a simplified API for building Shiny applications with automatic UI collection and streamlined syntax. It eliminates the need for explicit UI structure and server function definition, making it ideal for rapid prototyping and simple applications.
3
4
```python
5
# Required imports for this module
6
from shiny.express import app_opts, wrap_express_app, is_express_app, expressify, output_args
7
from shiny.express import input, output, ui, render
8
from shiny import App, Inputs, Outputs, Session
9
from typing import Callable, Literal, Mapping
10
from htmltools import Tag, TagList, TagChild
11
from pathlib import Path
12
```
13
14
## Capabilities
15
16
### Express Core Objects
17
18
Dynamic objects that provide session-dependent access to inputs, outputs, and session functionality.
19
20
```python { .api }
21
# Express mode core objects (session-dependent)
22
input: Inputs
23
"""
24
Dynamic input accessor that provides reactive access to user inputs.
25
Equivalent to the input parameter in core mode server functions.
26
"""
27
28
output: Outputs
29
"""
30
Dynamic output accessor for assigning rendered content.
31
Equivalent to the output parameter in core mode server functions.
32
"""
33
34
session: Session
35
"""
36
Dynamic session accessor for session management and client communication.
37
Equivalent to the session parameter in core mode server functions.
38
"""
39
40
render: ModuleType
41
"""
42
Rendering functions for creating reactive outputs.
43
Same as shiny.render module but optimized for Express mode.
44
"""
45
```
46
47
#### Usage Examples
48
49
```python
50
# Express mode application
51
from shiny.express import input, output, ui, render
52
53
# Direct UI definition (automatically collected)
54
ui.h1("Express Shiny App")
55
ui.input_slider("n", "Number of observations:", 0, 100, 20)
56
57
# Direct output rendering (automatically assigned)
58
@render.text
59
def txt():
60
return f"The value of n is {input.n()}"
61
62
# Access session directly
63
@render.text
64
def session_info():
65
return f"Session ID: {id(session)}"
66
67
# Multiple outputs
68
@render.plot
69
def histogram():
70
import matplotlib.pyplot as plt
71
import numpy as np
72
73
np.random.seed(19680801)
74
data = np.random.randn(input.n())
75
76
plt.hist(data, bins=30)
77
plt.title(f"Histogram of {input.n()} observations")
78
return plt.gcf()
79
80
@render.table
81
def summary():
82
import pandas as pd
83
import numpy as np
84
85
np.random.seed(19680801)
86
data = np.random.randn(input.n())
87
88
return pd.DataFrame({
89
"Statistic": ["Mean", "Std", "Min", "Max"],
90
"Value": [data.mean(), data.std(), data.min(), data.max()]
91
})
92
```
93
94
### Express Configuration
95
96
Functions for configuring Express mode applications.
97
98
```python { .api }
99
def app_opts(
100
*,
101
static_assets: str | Path | Mapping[str, str | Path] | None = None,
102
bookmark_store: Literal["url", "server", "disable"] | None = None,
103
debug: bool | None = None,
104
) -> None:
105
"""
106
Configure express app options.
107
108
Args:
109
static_assets: Path to static assets directory or mapping.
110
bookmark_store: Bookmark storage strategy.
111
debug: Enable debug mode.
112
"""
113
114
def wrap_express_app(file: Path) -> App:
115
"""
116
Wrap an express app file for deployment.
117
118
Args:
119
file: Path to the express app Python file.
120
121
Returns:
122
App instance suitable for deployment.
123
"""
124
125
def is_express_app(app: str, app_dir: str | None) -> bool:
126
"""
127
Check if the specified app is an express mode app.
128
129
Args:
130
app: The app filename to check.
131
app_dir: Directory containing the app file.
132
133
Returns:
134
True if it's an express mode app, False otherwise.
135
"""
136
137
def expressify(fn: Callable[..., T]) -> Callable[..., T]:
138
"""
139
Decorator for making functions work with Express mode's automatic display system.
140
141
Args:
142
fn: Function to make compatible with Express mode.
143
144
Returns:
145
Decorated function that works in Express mode.
146
"""
147
148
def output_args(**kwargs: object) -> Callable[[Callable[..., T]], Callable[..., T]]:
149
"""
150
Decorator for setting default UI arguments for rendering functions.
151
152
Args:
153
**kwargs: Default arguments to apply to the output UI.
154
155
Returns:
156
Decorator function.
157
"""
158
```
159
160
#### Usage Examples
161
162
```python
163
# Configure express app
164
from shiny.express import app_opts, ui, render, input
165
166
app_opts(
167
title="My Express App",
168
debug=True
169
)
170
171
ui.h1("Configured Express App")
172
ui.input_text("name", "Enter name:")
173
174
@render.text
175
def greeting():
176
return f"Hello, {input.name()}!"
177
178
# Wrap for deployment (in separate deployment script)
179
from shiny.express import wrap_express_app
180
181
app = wrap_express_app("my_express_app.py")
182
183
# Check if in express mode
184
from shiny.express import is_express_app
185
186
if is_express_app():
187
print("Running in Express mode")
188
else:
189
print("Running in Core mode")
190
191
# Function-based express app
192
from shiny.express import expressify
193
194
def my_app():
195
from shiny.express import ui, render, input
196
197
ui.h1("Function-based App")
198
ui.input_slider("x", "Value:", 1, 10, 5)
199
200
@render.text
201
def result():
202
return f"Value squared: {input.x() ** 2}"
203
204
app = expressify(my_app)
205
```
206
207
### Express UI Components
208
209
All UI components from the main `shiny.ui` module, plus Express-specific additions and context manager versions.
210
211
```python { .api }
212
def page_opts(**kwargs: object) -> None:
213
"""
214
Configure page-level options for express apps.
215
216
Args:
217
**kwargs: Page configuration options including:
218
- title: Page title
219
- lang: Page language
220
- theme: UI theme
221
"""
222
223
class hold:
224
"""
225
Context manager to hold UI element rendering until explicitly released.
226
"""
227
def __enter__(self) -> None:
228
"""Enter hold context."""
229
230
def __exit__(self, *args: object) -> None:
231
"""Exit hold context and render held elements."""
232
```
233
234
#### Context Manager Layouts
235
236
Express mode provides context manager versions of layout components for intuitive nested syntax:
237
238
```python { .api }
239
# Context manager versions of layout components
240
sidebar(*args: TagChild, **kwargs: TagAttr) -> ContextManager[None]
241
layout_sidebar(*args: TagChild, **kwargs: TagAttr) -> ContextManager[None]
242
card(*args: TagChild, **kwargs: TagAttr) -> ContextManager[None]
243
accordion(*args: TagChild, **kwargs: TagAttr) -> ContextManager[None]
244
nav_panel(title: str, *args: TagChild, **kwargs: TagAttr) -> ContextManager[None]
245
navset_tab(*args: TagChild, **kwargs: TagAttr) -> ContextManager[None]
246
layout_columns(*args: TagChild, **kwargs: TagAttr) -> ContextManager[None]
247
```
248
249
#### Usage Examples
250
251
```python
252
# Express UI with context managers
253
from shiny.express import ui, render, input
254
255
# Configure page
256
ui.page_opts(title="Express Layout Demo")
257
258
ui.h1("Express Layout Example")
259
260
# Sidebar layout with context manager
261
with ui.layout_sidebar():
262
with ui.sidebar():
263
ui.h3("Controls")
264
ui.input_select("dataset", "Dataset:", ["mtcars", "iris", "diamonds"])
265
ui.input_slider("n_rows", "Rows to show:", 5, 50, 10)
266
ui.input_checkbox("show_summary", "Show summary", False)
267
268
# Main content area
269
ui.h2("Data View")
270
271
# Cards with context manager
272
with ui.card():
273
ui.card_header("Dataset Preview")
274
275
@render.data_frame
276
def data_preview():
277
# Implementation here
278
pass
279
280
with ui.card():
281
ui.card_header("Visualization")
282
283
@render.plot
284
def data_plot():
285
# Implementation here
286
pass
287
288
# Navigation with context manager
289
with ui.navset_tab():
290
with ui.nav_panel("Data"):
291
ui.h3("Data Management")
292
ui.input_file("upload", "Upload CSV")
293
294
with ui.nav_panel("Analysis"):
295
ui.h3("Statistical Analysis")
296
297
with ui.layout_columns():
298
with ui.card():
299
ui.card_header("Options")
300
ui.input_checkbox_group(
301
"analyses",
302
"Select analyses:",
303
["correlation", "regression", "clustering"]
304
)
305
306
with ui.card():
307
ui.card_header("Results")
308
309
@render.text
310
def analysis_results():
311
return f"Selected: {input.analyses()}"
312
313
# Hold UI rendering
314
with ui.hold():
315
# These elements won't render until the context exits
316
ui.h3("Batch Rendered Elements")
317
ui.p("This content is rendered together")
318
319
for i in range(3):
320
ui.p(f"Item {i + 1}")
321
```
322
323
### Express Modules
324
325
Module system adapted for Express mode applications.
326
327
```python { .api }
328
module: object
329
"""
330
Module system for Express apps with decorators and utilities.
331
332
Provides:
333
- @module.ui decorator for module UI functions
334
- @module.server decorator for module server functions
335
- current_namespace() function
336
- resolve_id() function
337
"""
338
```
339
340
#### Usage Examples
341
342
```python
343
# Express module definition
344
from shiny.express import module, ui, render, input
345
346
# Module UI function
347
@module.ui
348
def counter_ui():
349
ui.h3("Counter Module")
350
ui.input_action_button("increment", "Increment")
351
ui.input_action_button("reset", "Reset")
352
ui.output_text("count")
353
354
# Module server function
355
@module.server
356
def counter_server(input, output, session):
357
count = reactive.value(0)
358
359
@reactive.effect
360
@reactive.event(input.increment)
361
def _():
362
count.set(count.get() + 1)
363
364
@reactive.effect
365
@reactive.event(input.reset)
366
def _():
367
count.set(0)
368
369
@output
370
@render.text
371
def count():
372
return f"Count: {count()}"
373
374
# Use module in main app
375
from shiny.express import ui
376
377
ui.h1("App with Modules")
378
379
# Include multiple instances of the module
380
counter_ui("counter1")
381
counter_server("counter1")
382
383
ui.hr()
384
385
counter_ui("counter2")
386
counter_server("counter2")
387
```
388
389
### Express Chat and Markdown
390
391
Express-compatible versions of interactive components.
392
393
```python { .api }
394
class Chat:
395
"""
396
Express-compatible chat interface.
397
398
Provides real-time chat functionality optimized for Express mode
399
with automatic UI integration and simplified message handling.
400
"""
401
def __init__(
402
self,
403
id: str,
404
messages: list[ChatMessage] | None = None,
405
**kwargs: object
406
): ...
407
408
def send_message(self, message: str, user: str = "assistant") -> None:
409
"""Send a message to the chat."""
410
411
def clear_messages(self) -> None:
412
"""Clear all chat messages."""
413
414
class MarkdownStream:
415
"""
416
Express-compatible markdown streaming component.
417
418
Provides streaming markdown rendering with real-time updates
419
optimized for Express mode applications.
420
"""
421
def __init__(self, id: str, **kwargs: object): ...
422
423
def write(self, content: str) -> None:
424
"""Write content to the markdown stream."""
425
426
def clear(self) -> None:
427
"""Clear the markdown stream."""
428
```
429
430
#### Usage Examples
431
432
```python
433
# Express chat application
434
from shiny.express import ui, render, input, Chat
435
436
ui.h1("Express Chat Demo")
437
438
# Create chat interface
439
chat = Chat(
440
id="main_chat",
441
messages=[
442
{"user": "assistant", "message": "Hello! How can I help you?"},
443
]
444
)
445
446
ui.input_text("user_message", "Type your message:", placeholder="Enter message...")
447
ui.input_action_button("send", "Send")
448
449
@reactive.effect
450
@reactive.event(input.send)
451
def handle_message():
452
message = input.user_message()
453
if message.strip():
454
# Add user message
455
chat.send_message(message, user="user")
456
457
# Simple echo response
458
response = f"You said: {message}"
459
chat.send_message(response, user="assistant")
460
461
# Clear input (would need session.send_input_message in real app)
462
463
# Streaming markdown example
464
from shiny.express import MarkdownStream
465
466
ui.h2("Streaming Content")
467
468
markdown_stream = MarkdownStream("content_stream")
469
470
ui.input_action_button("start_stream", "Start Streaming")
471
ui.input_action_button("clear_stream", "Clear")
472
473
@reactive.effect
474
@reactive.event(input.start_stream)
475
def start_streaming():
476
import asyncio
477
478
async def stream_content():
479
content_pieces = [
480
"# Streaming Demo\n\n",
481
"This content is being **streamed** in real-time.\n\n",
482
"- First item\n",
483
"- Second item\n",
484
"- Third item\n\n",
485
"## Code Example\n\n",
486
"```python\n",
487
"def hello():\n",
488
" print('Hello, World!')\n",
489
"```\n\n",
490
"Streaming complete! ๐"
491
]
492
493
for piece in content_pieces:
494
markdown_stream.write(piece)
495
await asyncio.sleep(0.5)
496
497
asyncio.create_task(stream_content())
498
499
@reactive.effect
500
@reactive.event(input.clear_stream)
501
def clear_content():
502
markdown_stream.clear()
503
```
504
505
### Express vs Core Mode Comparison
506
507
#### Core Mode Application
508
```python
509
from shiny import App, ui, render, Inputs, Outputs, Session
510
511
# Explicit UI definition
512
app_ui = ui.page_fluid(
513
ui.h1("Core Mode App"),
514
ui.input_slider("n", "Number:", 1, 10, 5),
515
ui.output_text("result")
516
)
517
518
# Explicit server function
519
def server(input: Inputs, output: Outputs, session: Session):
520
@output
521
@render.text
522
def result():
523
return f"Value: {input.n()}"
524
525
# Explicit app creation
526
app = App(app_ui, server)
527
```
528
529
#### Express Mode Application
530
```python
531
from shiny.express import ui, render, input
532
533
# Direct UI definition (automatically collected)
534
ui.h1("Express Mode App")
535
ui.input_slider("n", "Number:", 1, 10, 5)
536
537
# Direct output rendering (automatically assigned)
538
@render.text
539
def result():
540
return f"Value: {input.n()}"
541
542
# App automatically created from collected UI and outputs
543
```
544
545
### Express Mode Best Practices
546
547
1. **Use for Rapid Prototyping**: Express mode is ideal for quick demos and simple applications
548
2. **Context Managers**: Take advantage of context manager syntax for cleaner nested layouts
549
3. **Gradual Migration**: Start with Express mode and migrate to Core mode as complexity grows
550
4. **Module Organization**: Use Express modules to organize complex applications
551
5. **Debugging**: Use `is_express_app()` to write code that works in both modes
552
553
```python
554
# Adaptive code for both modes
555
from shiny.express import is_express_app
556
557
if is_express_app():
558
from shiny.express import input, output, session
559
else:
560
# In core mode, these come from server function parameters
561
pass
562
563
# Function that works in both modes
564
def get_user_greeting():
565
if is_express_app():
566
from shiny.express import input
567
return f"Hello, {input.username()}!"
568
else:
569
# Core mode would need input parameter passed in
570
raise RuntimeError("Must be called from within server function")
571
```