The Problem
The st.logo() function in Streamlit was limited to accepting only image files (PNG, JPG, SVG, etc.) for app branding. This created friction for developers who wanted a quick, lightweight way to add visual identity to their apps without managing external image assets.
The community requested the ability to use Material Design icons (e.g., :material/home:) and emoji characters (e.g., 🏠) directly in st.logo(), matching the flexibility already available in other Streamlit components like st.chat_message avatars.
Original issue: #13385 - opened by @arnaudmiribel
Proposed usage:
st.logo(":material/bath_outdoor:")
The Solution
Following guidance from Streamlit maintainer @lukasmasuch, I implemented the feature by reusing the existing DynamicIcon component from the frontend - the same pattern used for st.chat_message avatars. This approach avoided reinventing the wheel and ensured consistency across the Streamlit component library.
Implementation Details
Backend (Python):
- Added an
ImageTypeenum to the Logo protobuf with three options:IMAGE,EMOJI, andICON - Created a
_process_logo_image()helper function to detect whether the input is an image URL, Material icon string, or emoji character - Updated docstrings to document the new supported formats
Frontend (TypeScript/React):
- Modified
LogoComponent.tsxto conditionally renderDynamicIconfor icons/emojis instead of the standard<img>tag - Added
StyledIconLogostyled component for proper icon and emoji sizing - Implemented size mapping: logo sizes (small/medium/large) map to icon sizes (lg/xl/twoXL)
Usage Examples
# Material icon as logo
st.logo(":material/home:")
# Emoji as logo
st.logo("🏠")
# Material icon with link
st.logo(":material/rocket_launch:", link="https://streamlit.io")
# Image logo with icon as collapsed sidebar image
st.logo(full_logo_image, icon_image=":material/menu:")
Files Changed
| File | Change |
|---|---|
proto/streamlit/proto/Logo.proto | Added ImageType enum (IMAGE, EMOJI, ICON) |
lib/streamlit/commands/logo.py | Added _process_logo_image() helper function |
lib/tests/streamlit/commands/logo_test.py | 5 new unit tests for icons, emojis, links, mixed types, errors |
frontend/app/src/components/Logo/LogoComponent.tsx | Integrated DynamicIcon rendering |
frontend/app/src/components/Logo/LogoComponent.test.tsx | 4 new frontend tests |
frontend/app/src/components/Sidebar/styled-components.ts | Added StyledIconLogo component |
Test Coverage
- Python tests: 5 unit tests covering material icons, emojis, links, mixed logo/icon types, and error handling
- Frontend tests: 4 tests verifying
DynamicIconrendering behavior for different input types - E2E tests: Relied on existing
DynamicIconcomponent coverage
Timeline
| Date | Event |
|---|---|
| 2025-12-16 | Issue #13385 opened by @arnaudmiribel |
| 2025-12-19 | PR #13416 opened with full implementation |
| 2025-12-19 | Added Python and frontend test coverage |
| 2025-12-19 | Addressed review feedback on icon size mapping |
Current Status
The PR is currently awaiting:
- Product team approval (
status:needs-product-approval) - Visual demonstration of the feature with different emojis, icons, and size parameters
Review feedback addressed: Fixed a TypeScript import issue where IconSize was being imported from @streamlit/lib instead of the internal path alias ~lib/theme.