Skip to content

feat(logo): add support for Material icons and emojis in st.logo#13416

Merged
lukasmasuch merged 15 commits intostreamlit:developfrom
rahuld109:feat/logo-icon-support
Jan 27, 2026
Merged

feat(logo): add support for Material icons and emojis in st.logo#13416
lukasmasuch merged 15 commits intostreamlit:developfrom
rahuld109:feat/logo-icon-support

Conversation

@rahuld109
Copy link
Copy Markdown
Contributor

@rahuld109 rahuld109 commented Dec 19, 2025

Describe your changes

Adds support for Material icons and emojis in st.logo():

st.logo(":material/home:")
st.logo("🏠")
st.logo(":material/rocket_launch:", link="https://streamlit.io")
st.logo(full_logo, icon_image=":material/menu:")

Following @lukasmasuch's suggestion, this passes the icon name to the frontend and reuses the existing DynamicIcon component (same pattern st.chat_message uses for avatars).

Changes:

  • New ImageType enum in Logo protobuf (IMAGE/EMOJI/ICON)
  • _process_logo_image() helper to detect input type
  • Frontend LogoComponent renders DynamicIcon for icons/emojis
  • New StyledIconLogo styled component for sizing

Screenshots

Material Icons - Size Parameter (small / medium / large)

Small Medium Large
!small !medium !large

Different Material Icons

:material/home: :material/favorite:
!home !favorite

Emoji Support

!emoji

GitHub Issue Link (if applicable)

Closes #13385

Testing Plan

  • Unit Tests (JS and/or Python)
    • Added 5 Python tests for icons, emojis, icon with link, icon_image as icon, and invalid icon
    • Added 4 frontend tests for DynamicIcon rendering with ICON/EMOJI types
  • E2E Tests: Not added - relies on existing DynamicIcon E2E coverage
  • Manual testing: Verified icons and emojis render correctly in sidebar

Contribution License Agreement

By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.

@rahuld109 rahuld109 requested a review from a team as a code owner December 19, 2025 08:07
@snyk-io
Copy link
Copy Markdown
Contributor

snyk-io bot commented Dec 19, 2025

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@github-actions
Copy link
Copy Markdown
Contributor

Thanks for contributing to Streamlit! 🎈

Please make sure you have read our Contributing Guide. You can find additional information about Streamlit development in the wiki.

The review process:

  1. Initial triage: A maintainer will apply labels, approve CI to run, and trigger AI-assisted reviews. Your PR may be flagged with status:needs-product-approval if the feature requires product team sign-off.

  2. Code review: A core maintainer will start reviewing your PR once:

    • It is marked as 'ready for review', not 'draft'
    • It has status:product-approved (or doesn't need it)
    • All CI checks pass
    • All AI review comments are addressed

We're receiving many contributions and have limited review bandwidth — please expect some delay. We appreciate your patience! 🙏

@lukasmasuch lukasmasuch requested a review from Copilot December 19, 2025 08:24
@lukasmasuch
Copy link
Copy Markdown
Collaborator

@cursor review

@lukasmasuch lukasmasuch added change:feature PR contains new feature or enhancement implementation impact:users PR changes affect end users status:needs-product-approval PR requires product approval before merging labels Dec 19, 2025
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for Material icons and emojis in st.logo(), allowing users to pass icon strings (:material/home:) or emoji characters (🏠) instead of only image files. The implementation reuses the existing DynamicIcon component pattern from st.chat_message avatars.

Key Changes:

  • Added ImageType enum (IMAGE/EMOJI/ICON) to Logo protobuf with backward-compatible field numbering
  • Created _process_logo_image() helper function to detect and validate input type (image/emoji/icon)
  • Modified frontend LogoComponent to render DynamicIcon for icons/emojis instead of <img> tags

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
proto/streamlit/proto/Logo.proto Added ImageType enum and two new fields (image_type, icon_image_type) to support icon/emoji detection
lib/streamlit/commands/logo.py Added _process_logo_image() helper and updated logo() to handle emoji/icon strings, with updated docstrings
lib/tests/streamlit/commands/logo_test.py Added 5 Python tests covering material icons, emojis, icons with links, mixed icon types, and invalid icons
frontend/app/src/components/Logo/LogoComponent.tsx Added conditional rendering logic to use DynamicIcon when imageType is ICON or EMOJI
frontend/app/src/components/Logo/LogoComponent.test.tsx Added 4 frontend tests verifying DynamicIcon rendering for ICON/EMOJI types
frontend/app/src/components/Sidebar/styled-components.ts Added StyledIconLogo styled component for sizing icon/emoji logos

Add support for using Material icons (e.g., `:material/home:`) and
emojis (e.g., `🏠`) as logos in `st.logo()`, in addition to image files.

Changes:
- Add ImageType enum to Logo protobuf (IMAGE, EMOJI, ICON)
- Add _process_logo_image() helper to detect and process icon/emoji/image
- Integrate DynamicIcon component in frontend LogoComponent
- Add StyledIconLogo styled component for icon/emoji rendering
- Update docstrings to document new supported formats

Closes streamlit#13385
- Map logo size (small/medium/large) to DynamicIcon size (lg/xl/twoXL)
- Fix type annotation for image parameter to accept str for emoji/icons
@rahuld109 rahuld109 force-pushed the feat/logo-icon-support branch from 0cc4f94 to db0e0d5 Compare December 19, 2025 17:30
@jrieke jrieke added the missing:visual-demonstration PR should include a video or screenshots showing how the feature/fix works label Dec 30, 2025
@jrieke
Copy link
Copy Markdown
Collaborator

jrieke commented Dec 30, 2025

Can you please add some screenshots of what this looks like with different emojis and icons, and different values for the size parameter of st.logo?

@github-actions
Copy link
Copy Markdown
Contributor

Summary

This PR adds support for Material icons and emojis in st.logo(), allowing users to use icons like :material/home: or emojis like 🏠 in addition to image files. The implementation follows the same pattern used by st.chat_message for avatars, reusing the existing DynamicIcon component on the frontend.

Key changes:

  • Added new ImageType enum to the Logo protobuf (IMAGE/EMOJI/ICON)
  • Created _process_logo_image() helper in Python to detect input type
  • Updated LogoComponent.tsx to render DynamicIcon for icons/emojis
  • Added new StyledIconLogo styled component for sizing

Code Quality

Critical Issue: TypeScript Import Error

File: frontend/app/src/components/Logo/LogoComponent.tsx, Line 35

import { IconSize } from "@streamlit/lib"

This import will fail at compile-time because IconSize is not exported from @streamlit/lib's public API (frontend/lib/src/index.ts). The index.ts only exports specific types from the theme module:

export type { EmotionTheme, PresetThemeName, ThemeConfig } from "./theme"

Fix: Change the import to use the internal path alias available in the app package:

import { IconSize } from "~lib/theme"

This is consistent with how other files in the codebase import IconSize (e.g., DynamicIcon.tsx).

Code Structure (Good)

  1. Static data structure at module level ✅ - LOGO_SIZE_TO_ICON_SIZE mapping is correctly defined at module level (line 40-44), following the TypeScript best practices.

  2. Clean separation of concerns ✅ - The _process_logo_image() helper function in Python cleanly separates the detection logic.

  3. Consistent with existing patterns ✅ - The implementation follows the same approach used by st.chat_message for rendering icons/emojis.

Minor Observations

  1. StyledIconLogo (styled-components.ts, lines 201-215): Uses == for comparison instead of ===. While this works in TypeScript, it's generally recommended to use strict equality:

    marginTop: size == "small" ? theme.spacing.xs : theme.spacing.twoXS,

    Should be:

    marginTop: size === "small" ? theme.spacing.xs : theme.spacing.twoXS,

    (Note: This is consistent with the existing StyledLogo component, so it matches the codebase style)

  2. Type annotation in Python - The _process_logo_image function correctly uses proper return type annotations following the codebase conventions.

Test Coverage

Python Unit Tests ✅

The Python tests in lib/tests/streamlit/commands/logo_test.py are comprehensive:

  • test_material_icon - Tests basic material icon usage
  • test_emoji - Tests emoji usage
  • test_material_icon_with_link - Tests icon with link combination
  • test_icon_with_icon_image - Tests mixed image/icon scenario
  • test_invalid_material_icon - Tests error handling for invalid icons

All tests include docstrings following the best practices. The tests verify both the image_type field values and the actual image content.

Frontend Unit Tests ✅

The frontend tests in LogoComponent.test.tsx adequately cover the new functionality:

  • Tests DynamicIcon rendering when imageType is ICON
  • Tests DynamicIcon rendering when imageType is EMOJI
  • Tests img tag rendering when imageType is IMAGE (default)
  • Tests iconImageType usage when collapsed with mixed types

The tests follow RTL best practices, using getByTestId and asserting on element behavior rather than implementation details.

E2E Tests

No new E2E tests were added. The PR description mentions this is intentional since the feature "relies on existing DynamicIcon E2E coverage." This is acceptable given:

  1. The DynamicIcon component already has E2E coverage
  2. The existing st_logo E2E tests cover the logo rendering scenarios
  3. The unit tests provide adequate coverage for the new icon/emoji detection logic

However, consider adding at least one E2E test case with icon/emoji logos to verify the full integration.

Backwards Compatibility

Assessment: Fully backwards compatible

  1. Protobuf changes are additive - The new image_type and icon_image_type fields use the next available field numbers (5 and 6). The default value for the enum is IMAGE = 0, which means existing messages without these fields will default to image behavior.

  2. API signature changes are compatible - The image and icon_image parameters now accept str in addition to AtomicImage, which is a widening change. Existing code using image files will continue to work.

  3. Frontend gracefully handles missing types - The isIconOrEmoji check defaults to image rendering when the type is unspecified (proto default is 0/IMAGE).

Security & Risk

No security concerns identified.

  1. The icon validation uses existing validate_material_icon() function which validates against the known icon set
  2. Emoji validation uses the existing is_emoji() function
  3. No new external inputs or attack surfaces introduced
  4. The DynamicIcon component already handles sanitization for material icons and emojis

Regression risk: Low

  • The changes are well-encapsulated
  • Existing image-based logos are unaffected (default behavior preserved)
  • The reuse of DynamicIcon is a proven component

Recommendations

  1. [REQUIRED] Fix the TypeScript import error:

    In frontend/app/src/components/Logo/LogoComponent.tsx, change line 35 from:

    import { IconSize } from "@streamlit/lib"

    to:

    import { IconSize } from "~lib/theme"
  2. [OPTIONAL] Consider adding E2E test coverage:

    Add a test case in e2e_playwright/st_logo.py and st_logo_test.py to verify material icon or emoji logo rendering in the full stack, e.g.:

    def icon_logo_subtest():
        st.logo(":material/rocket_launch:")
        st.sidebar.write("Hi")
  3. [OPTIONAL] Consider exporting IconSize from @streamlit/lib:

    If IconSize is needed by the app package, it might be worth adding it to the public exports in frontend/lib/src/index.ts for consistency. However, fixing the import to use the internal path alias is the simpler solution.

Verdict

CHANGES REQUESTED: The PR has a critical TypeScript import error that will cause a build failure. The import of IconSize from @streamlit/lib must be fixed to use the internal path alias ~lib/theme before this PR can be merged. All other aspects of the implementation are well-done and follow the codebase conventions.


This is an automated AI review. Please verify the feedback and use your judgment.

@github-actions github-actions bot added the do-not-merge PR is blocked from merging label Dec 31, 2025
@rahuld109 rahuld109 marked this pull request as draft January 16, 2026 02:49
@rahuld109 rahuld109 marked this pull request as ready for review January 17, 2026 00:01
@rahuld109
Copy link
Copy Markdown
Contributor Author

Hey @jrieke @lukasmasuch, apologies for going quiet on this one - life got in the way for a bit!

I've made all the updates:

  • Screenshots: Added to the PR description showing material icons at different sizes and emoji support
  • Edge case tests: Covered invalid icons, empty strings, and invalid input handling
  • E2E tests: Added tests for both material icon and emoji logo rendering

Let me know if there's anything else - always happy to help!

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no bugs!

@rahuld109
Copy link
Copy Markdown
Contributor Author

@jrieke please can you remove missing:visual-demonstration label or I need to add any more visuals documentation. Thanks

@jrieke jrieke added status:product-approved Community PR is approved by product team and removed missing:visual-demonstration PR should include a video or screenshots showing how the feature/fix works status:needs-product-approval PR requires product approval before merging labels Jan 27, 2026
@jrieke
Copy link
Copy Markdown
Collaborator

jrieke commented Jan 27, 2026

Sorry for the delay. Reviewed the screenshots and they look good, approved from product side! Will send this to our eng team to review.

@github-actions
Copy link
Copy Markdown
Contributor

Summary

Adds emoji and Material icon support to st.logo by extending the Logo proto with image type metadata and rendering icons via DynamicIcon, plus new Python/TS unit tests and e2e snapshots for icon/emoji cases.

Code Quality

  • lib/streamlit/commands/logo.py lines 40-77: _process_logo_image sends any non-emoji, non-:material string to image_to_url, which accepts empty or plain strings and returns a media URL. That means st.logo("") and st.logo("hello") will not raise, contradicting the new tests in lib/tests/streamlit/commands/logo_test.py lines 195-203. Add explicit validation for empty/non-file/non-URL strings or revise those tests/docs to align with existing st.image semantics.
  • frontend/app/src/components/Logo/LogoComponent.tsx lines 118-149: when appLogo.link is set and the logo is an emoji/icon, the <a> element lacks an accessible name because the icon content is aria-hidden for emojis. This violates the a11y rule for icon-only links and makes the logo link inaccessible.

Test Coverage

Python unit tests cover icon/emoji cases and invalid inputs; frontend unit tests cover icon/emoji rendering and collapsed behavior; e2e snapshots cover icon and emoji logos. The new e2e tests for icon/emoji do not include a “must NOT happen” assertion as recommended in e2e_playwright guidance (e.g., assert no <img> renders when image_type is ICON/EMOJI).

Backwards Compatibility

Proto changes are additive and should be wire-compatible. Note that emoji/icon logos will render as broken images on older frontends that don’t understand image_type if mixed versions are possible.

Security & Risk

No direct security concerns. Accepting arbitrary strings as logo images can still produce invalid media content (broken images) if the string is not a valid file/URL/emoji/icon.

Recommendations

  1. Enforce validation in _process_logo_image for empty and non-URL/non-file strings, or update the new tests to match st.image semantics. (lib/streamlit/commands/logo.py, lib/tests/streamlit/commands/logo_test.py)
  2. Add an accessible name for the logo link when rendering icon/emoji logos (e.g., aria-label="Logo link" or a label derived from context). (frontend/app/src/components/Logo/LogoComponent.tsx)
  3. Add a negative assertion in the new e2e icon/emoji tests to match the e2e best-practice checklist (e.g., no <img> for icon/emoji logos). (e2e_playwright/st_logo_test.py)

Verdict

CHANGES_REQUESTED: Fix the invalid-string handling and the logo link accessibility before merge.


This is an automated AI review using gpt-5.2-codex-high. Please verify the feedback and use your judgment.

@lukasmasuch lukasmasuch removed the do-not-merge PR is blocked from merging label Jan 27, 2026
Copy link
Copy Markdown
Collaborator

@lukasmasuch lukasmasuch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍 Thanks for the contribution.

@lukasmasuch lukasmasuch enabled auto-merge (squash) January 27, 2026 01:54
@lukasmasuch lukasmasuch merged commit a27d52d into streamlit:develop Jan 27, 2026
48 of 50 checks passed
@rahuld109 rahuld109 deleted the feat/logo-icon-support branch January 27, 2026 08:49
@jrieke
Copy link
Copy Markdown
Collaborator

jrieke commented Jan 27, 2026

Awesome, thanks for the contribution! @rahuld109 would love to send you some swag as a little thank you, feel free to fill out this form: https://docs.google.com/forms/d/e/1FAIpQLSe7cXh3H1DmrgNpVew9qViGIHX7vdEbTv5isA44_z5bgaKTKg/viewform

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:feature PR contains new feature or enhancement implementation impact:users PR changes affect end users status:product-approved Community PR is approved by product team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support icon in st.logo

5 participants