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 |
| 2026-01-27 | PR merged into Streamlit |
| 2026-02-19 | Received contributor swag from Streamlit |
Current Status
The PR was merged on January 27, 2026. The feature is now part of Streamlit, allowing developers to use Material icons and emojis directly in st.logo().
Review feedback addressed: Fixed a TypeScript import issue where IconSize was being imported from @streamlit/lib instead of the internal path alias ~lib/theme.