Add keyboard shortcuts to your Streamlit buttons! π
Note
v1.2.0 - Multiple Shortcuts per Button
- Added support for multiple shortcuts per button/widget (#34)
- Use lists to assign multiple shortcuts:
shortcut_button("Save", ["ctrl+s", "cmd+s"])
- Works with both
shortcut_button
andadd_shortcuts
# Before using native st.button:
if st.button("Save", type="primary", use_container_width=True):
save()
# After (just change function name & add shortcut):
if shortcut_button("Save", "ctrl+s", type="primary", use_container_width=True):
save()
# Multiple shortcuts for one button
if shortcut_button("Previous", ["arrowleft", "h"]):
go_previous()
name = st.text_input("Name", key="name_input")
# Add shortcuts to any widget with a key
add_shortcuts(
name_input="ctrl+n", # Focus name field
)
Check out the live demo or view the example code
pip install streamlit-shortcuts
Drop-in replacement for st.button
with keyboard shortcut support.
Parameters:
label
(str): Button textshortcut
(str | list[str]): Single shortcut or list of shortcuts (e.g., "ctrl+s", ["ctrl+s", "cmd+s"])key
(str, optional): Unique key for the buttonhint
(bool, optional): Show shortcut hint in button label (default: True)**kwargs
: All other st.button parameters (help, on_click, args, type, icon, disabled, use_container_width)
Returns: bool - True if clicked
Add keyboard shortcuts to any Streamlit widgets.
Parameters:
**shortcuts
: Keyword arguments where key is the widget's key and value is the shortcut (str | list[str])
Example:
add_shortcuts(
save_btn="ctrl+s",
search_input="ctrl+f",
submit_form="ctrl+enter"
)
# Multiple shortcuts per widget
add_shortcuts(
prev_btn=["arrowleft", "a"],
next_btn=["arrowright", "d"]
)
Remove all keyboard shortcuts and event listeners. Useful for:
- Multi-page apps when switching pages
- Conditionally disabling all shortcuts
- Cleaning up shortcuts in dynamic UIs
Example:
# Disable shortcuts conditionally
if not shortcuts_enabled:
clear_shortcuts()
# Clean up when switching pages
if st.sidebar.button("Go to Settings"):
clear_shortcuts()
st.switch_page("settings")
- Modifiers:
ctrl
,alt
,shift
,meta
(cmd on Mac) - Common keys:
enter
,escape
,space
,tab
,delete
- Letters:
a
-z
- Numbers:
0
-9
- Function keys:
f1
-f12
- Arrow keys:
arrowleft
,arrowright
,arrowup
,arrowdown
ctrl+s
- Ctrl + Sctrl+shift+d
- Ctrl + Shift + Dalt+enter
- Alt + Enterf1
- F1 key
- On macOS,
ctrl
works as expected (not cmd) - For OS-specific shortcuts, use
meta
(Windows key on PC, Cmd on Mac) - Some shortcuts may conflict with browser/OS shortcuts
When using shortcut_button
inside columns with vertical_alignment
, the button may not align properly. This happens because the shortcut injection creates an invisible element that affects layout.
Workaround: Use st.button
with add_shortcuts
separately:
# β Broken alignment
col1, col2 = st.columns([1, 1], vertical_alignment="bottom")
with col1:
shortcut_button("Save", "ctrl+s")
with col2:
st.selectbox("Options", ["A", "B", "C"])
# β
Correct alignment
col1, col2 = st.columns([1, 1], vertical_alignment="bottom")
with col1:
st.button("Save", key="save_btn")
with col2:
st.selectbox("Options", ["A", "B", "C"])
# Add shortcuts after columns
add_shortcuts(save_btn="ctrl+s")
- β No more API hijacking - v0.x monkey-patched Streamlit's API. Now we respect it:
# v0.x - Hijacked the API, confusing and unpythonic button("Save", "ctrl+s", lambda: save()) # What is this? Not st.button! # v1.0 - Respects Streamlit patterns, works like st.button if shortcut_button("Save", "ctrl+s"): # Familiar pattern! save() # Or use native st.button unchanged if st.button("Save", key="save_btn"): save() add_shortcuts(save_btn="ctrl+s")
- π From 277 lines β 91 lines total (across 5 Python files β 1 file)
- ποΈ Removed 15 files of configuration bloat
- π No more src/ directory - just one flat file
- β Deleted all tests - meaningless tests that tested nothing, replaced with assertions that actually fail
- π₯ Modern Python tooling - replaced setup.py/MANIFEST/VERSION with pyproject.toml + uv
- π§Ή Ruff instead of 5 linters - removed flake8, black, isort, mypy, pre-commit hooks
- β‘ 3 workflows β 1 workflow - simple CI/CD
If upgrading from v0.x:
# Old v0.x API
button("Click me", "ctrl+k", lambda: st.write("Hi"))
# New v1.0 API
if shortcut_button("Click me", "ctrl+k"):
st.write("Hi")
# Or use st.button + add_shortcuts
if st.button("Click me", key="btn"):
st.write("Hi")
add_shortcuts(btn="ctrl+k")
Built by the Streamlit community! π
Special thanks to:
- @brunomsantiago and @TomJohnH for the initial concept
- @toolittlecakes for Meta key support
- @quantum-ernest for keyboard hints
- @sammlapp for making shortcuts work with any widget
- @jcbize for improved error handling
- @csipapicsa for identifying a XSS vulnerability
Inspired by Streamlit discussion #1291