Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions content/develop/api-reference/layout/expander.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ keywords: st.expander, expander, collapsible container, expandable container, ac
---

<Autofunction function="streamlit.expander" />

<Autofunction function="ExpanderContainer" />
2 changes: 2 additions & 0 deletions content/develop/api-reference/layout/popover.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ keywords: st.popover, popover, popup container, overlay container, floating cont
---

<Autofunction function="streamlit.popover" />

<Autofunction function="PopoverContainer" />
2 changes: 2 additions & 0 deletions content/develop/api-reference/layout/tabs.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ keywords: st.tabs, tabs, tab container, tabbed interface, tab navigation, tabbed
---

<Autofunction function="streamlit.tabs" />

<Autofunction function="TabContainer" />
16 changes: 12 additions & 4 deletions content/develop/concepts/app-design/_index.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
---
title: App design concepts and considerations
slug: /develop/concepts/design
description: Explore comprehensive guides about app design including animating elements, button behavior, custom styling, dataframe design, multithreading, and timezone handling.
keywords: app design, streamlit design, ui design, button behavior, custom styling, dataframes, multithreading, timezone handling, app layout, user experience
description: Explore comprehensive guides about app design including layouts and containers, updating elements, button behavior, custom styling, dataframe design, multithreading, and timezone handling.
keywords: app design, streamlit design, ui design, layouts, containers, button behavior, custom styling, dataframes, multithreading, timezone handling, app layout, user experience
---

# App design concepts and considerations

<TileContainer layout="list">

<RefCard href="/develop/concepts/design/layouts-and-containers">

<h5>Using layouts and containers</h5>

Arrange and organize elements with columns, tabs, expanders, flex layouts, and dynamic containers.

</RefCard>

<RefCard href="/develop/concepts/design/animate">

<h5>Animate and update elements</h5>
<h5>Update and replace elements</h5>

Understand how to create dynamic, animated content or update elements without rerunning your app.
Understand how Streamlit commands return objects you can use to update, replace, or clear elements in place.

</RefCard>

Expand Down
213 changes: 187 additions & 26 deletions content/develop/concepts/app-design/animate-elements.md
Original file line number Diff line number Diff line change
@@ -1,49 +1,210 @@
---
title: Animate and update elements
title: Update and replace elements
slug: /develop/concepts/design/animate
description: Learn how to create dynamic, animated content in Streamlit by updating elements in-place using st.empty, st.add_rows, and other updatable containers without full app reruns.
keywords: animate elements, update elements, st.empty, st.add_rows, dynamic content, live updates, in-place updates, streaming data, real-time updates, element animation
description: Learn how Streamlit commands return objects you can use to update, replace, or clear elements in place. Understand the difference between element objects, container objects, widget values, and widget-mode elements.
keywords: element objects, update elements, replace elements, st.empty, add_rows, dynamic content, live updates, in-place updates, containers, widgets, widget mode
---

# Animate and update elements
# Update and replace elements

Sometimes you display a chart or dataframe and want to modify it live as the app
runs (for example, in a loop). Some elements have built-in methods to allow you
to update them in-place without rerunning the app.
Most Streamlit commands draw something on the screen, and most commands also return an object. What that object is — and what you can do with it — depends on the type of command. Understanding this is the key to updating your app's display in place without triggering a full rerun.

Updatable elements include the following:
## Elements, containers, and widgets

- `st.empty` containers can be written to in sequence and will always show the last thing written. They can also be cleared with an
additional `.empty()` called like a method.
- `st.dataframe`, `st.table`, and many chart elements can be updated with the `.add_rows()` method which appends data.
- `st.progress` elements can be updated with additional `.progress()` calls. They can also be cleared with a `.empty()` method call.
- `st.status` containers have an `.update()` method to change their labels, expanded state, and status.
- `st.toast` messages can be updated in place with additional `.toast()` calls.
Streamlit commands fall into three categories based on what they return:

## `st.empty` containers
### Element commands

`st.empty` can hold a single element. When you write any element to an `st.empty` container, Streamlit discards its previous content
displays the new element. You can also `st.empty` containers by calling `.empty()` as a method. If you want to update a set of elements, use
a plain container (`st.container()`) inside `st.empty` and write contents to the plain container. Rewrite the plain container and its
contents as often as desired to update your app's display.
Commands like `st.markdown`, `st.image`, `st.dataframe`, and `st.line_chart` draw a single visible element. They return an **element object**, an object you can use to replace or clear that element later:

## The `.add_rows()` method
```python
import streamlit as st

el = st.text("Loading...")
# Later, replace the text with something else:
el.write("Done!")
```

`st.dataframe`, `st.table`, and all chart functions can be mutated using the `.add_rows()` method on their output. In the following example, we use `my_data_element = st.line_chart(df)`. You can try the example with `st.table`, `st.dataframe`, and most of the other simple charts by just swapping out `st.line_chart`. Note that `st.dataframe` only shows the first ten rows by default and enables scrolling for additional rows. This means adding rows is not as visually apparent as it is with `st.table` or the chart elements.
You can call `.empty()` on any element object to clear it from the screen:

```python
import streamlit as st

el = st.text("Temporary message")
el.empty()
```

### Container commands

Commands like `st.container`, `st.columns`, `st.tabs`, and `st.empty` create regions that hold other elements. They return a **container object** that you can write into using method calls or context managers:

```python
import streamlit as st

c = st.container()
c.write("Written via method call")

with c:
st.write("Written via context manager")
```

`st.empty` is a special container that holds only one element at a time. Each write to an `st.empty` object replaces the previous content. This makes it the primary tool for in-place updates. For more on containers, see [Using layouts and containers](/develop/concepts/design/layouts-and-containers).

### Widget commands

Commands like `st.slider`, `st.selectbox`, `st.button`, and `st.text_input` are widgets. They return a **Python value** like `int`, `str`, or `bool` instead of an abstract Streamlit object. You interact with widget state through `st.session_state` and callbacks, not by calling methods on their returned values:

```python
import streamlit as st

val = st.slider("Pick a number", 0, 100)
st.write(f"You picked {val}")
```

For details on how widgets manage state and identity, see [Widget behavior](/develop/concepts/architecture/widget-behavior).

### Widget-mode elements

Some elements can switch into **widget mode** when configured with interactive parameters. In widget mode, the element either returns its state directly, or its usual element object has state attributes. Elements in widget mode follow widget rules with respect to keys, callbacks, and Session State.

For example, `st.dataframe` normally returns an element object. However, when you set `on_select="rerun"`, it returns a selection dictionary instead:

```python
import streamlit as st
import pandas as pd

df = pd.DataFrame({"Name": ["Alice", "Bob"], "Score": [85, 92]})

# Default mode: returns an element object
el = st.dataframe(df)

# Widget mode: returns a selection dictionary
selection = st.dataframe(df, on_select="rerun", key="my_table")
st.write(selection)
```

Similarly, `st.tabs`, `st.expander`, and `st.popover` become widget-like when you set `on_change`. They still return container objects, but they also track state, which is available as attributes on the container objects. See [Dynamic containers](/develop/concepts/design/layouts-and-containers#dynamic-containers) for details.

## Replacing and clearing elements

The most common pattern for in-place updates is using `st.empty`:

```python
import streamlit as st
import time

placeholder = st.empty()

for i in range(5):
placeholder.write(f"Iteration {i}")
time.sleep(0.5)

placeholder.empty()
```

To replace a group of elements, nest `st.container` inside `st.empty`:

```python
import streamlit as st
import time

placeholder = st.empty()

with placeholder.container():
st.write("First set of content")
st.button("A button")

time.sleep(2)

with placeholder:
st.write("Replacement content")
```

Any element (not just `st.empty`) supports replacement and clearing. This works because every non-widget Streamlit command returns an element object for the position it occupies in the app:

```python
import streamlit as st

el = st.text("Loading...")
# Later, replace the text with something else:
el.write("Done!")
```

## Updating specific element types

Some elements have specialized update methods beyond replacement:

### `st.progress`

Update a progress bar by calling `.progress()` on the returned object. Clear it with `.empty()`:

```python
import streamlit as st
import time

bar = st.progress(0, text="Working...")

for i in range(100):
time.sleep(0.02)
bar.progress(i + 1, text=f"Working... {i + 1}%")

bar.empty()
```

### `st.status`

Update a status container's label, state, and expanded state with `.update()`:

```python
import streamlit as st
import time

with st.status("Downloading data...", expanded=True) as status:
st.write("Searching for data...")
time.sleep(1)
st.write("Downloading...")
time.sleep(1)
status.update(label="Download complete!", state="complete", expanded=False)
```

### `st.toast`

Update a toast notification in place by calling `.toast()` on the returned object:

```python
import streamlit as st
import time

msg = st.toast("Starting process...")
time.sleep(1)
msg.toast("Almost there...")
time.sleep(1)
msg.toast("Done!", icon="✅")
```

## Appending data with `.add_rows()`

`st.dataframe`, `st.table`, and basic chart elements like `st.line_chart` support an `.add_rows()` method that appends data to the element without replacing it. This is useful for streaming data or building up a chart incrementally:

```python
import streamlit as st
import pandas as pd
import numpy as np
import time

df = pd.DataFrame(np.random.randn(15, 3), columns=(["A", "B", "C"]))
my_data_element = st.line_chart(df)
df = pd.DataFrame(np.random.randn(15, 3), columns=["A", "B", "C"])
chart = st.line_chart(df)

for tick in range(10):
time.sleep(.5)
add_df = pd.DataFrame(np.random.randn(1, 3), columns=(["A", "B", "C"]))
my_data_element.add_rows(add_df)
time.sleep(0.5)
new_row = pd.DataFrame(np.random.randn(1, 3), columns=["A", "B", "C"])
chart.add_rows(new_row)

st.button("Regenerate")
```

<Note>

The Streamlit team is evaluating the future of `.add_rows()`. If you use this method, please share your feedback in the [community discussion](https://github.com/streamlit/streamlit/issues/13063).

</Note>
Loading