Skip to main content
Back to contributions
Pull Request
Open
43.1K

Add Material icon and emoji support to st.logo

streamlit/streamlit

Extended st.logo() to support Material icons and emojis in addition to image files

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 ImageType enum to the Logo protobuf with three options: IMAGE, EMOJI, and ICON
  • 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.tsx to conditionally render DynamicIcon for icons/emojis instead of the standard <img> tag
  • Added StyledIconLogo styled 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

FileChange
proto/streamlit/proto/Logo.protoAdded ImageType enum (IMAGE, EMOJI, ICON)
lib/streamlit/commands/logo.pyAdded _process_logo_image() helper function
lib/tests/streamlit/commands/logo_test.py5 new unit tests for icons, emojis, links, mixed types, errors
frontend/app/src/components/Logo/LogoComponent.tsxIntegrated DynamicIcon rendering
frontend/app/src/components/Logo/LogoComponent.test.tsx4 new frontend tests
frontend/app/src/components/Sidebar/styled-components.tsAdded 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 DynamicIcon rendering behavior for different input types
  • E2E tests: Relied on existing DynamicIcon component coverage

Timeline

DateEvent
2025-12-16Issue #13385 opened by @arnaudmiribel
2025-12-19PR #13416 opened with full implementation
2025-12-19Added Python and frontend test coverage
2025-12-19Addressed 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.