[feature] Add title parameter to alert elements#14665
Conversation
Add a `title` parameter to st.error, st.warning, st.info, and st.success to display a title above the body text. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
✅ PR preview is ready!
|
There was a problem hiding this comment.
Pull request overview
Adds an optional title parameter to Streamlit’s alert/status callouts (st.error, st.warning, st.info, st.success) so users can render a bold title above the existing Markdown body.
Changes:
- Extends the
Alertprotobuf with a newtitlefield and wires it through backend → frontend rendering. - Updates the Python alert APIs + docstrings to accept
titleand populate the proto field. - Adds/updates unit + frontend + E2E coverage for title rendering (including snapshots).
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| proto/streamlit/proto/Alert.proto | Adds title field to the Alert message for backend↔frontend transport. |
| lib/streamlit/elements/alert.py | Adds title kwarg to alert methods and sets alert_proto.title after cleaning. |
| lib/tests/streamlit/elements/alert_test.py | Adds Python unit tests verifying title propagation/cleaning across all alert variants. |
| frontend/lib/src/components/elements/AlertElement/styled-components.tsx | Introduces styled wrappers for title + body layout. |
| frontend/lib/src/components/elements/AlertElement/AlertElement.tsx | Renders an optional title above Markdown body and adjusts layout with/without icon. |
| frontend/lib/src/components/elements/AlertElement/AlertElement.test.tsx | Adds RTL tests verifying title presence/absence and title+icon cases. |
| frontend/lib/src/components/core/Block/ElementNodeRenderer.tsx | Passes alertProto.title into AlertElement. |
| e2e_playwright/st_alert.py | Adds new fixture app cases covering titled alerts (with and without icons). |
| e2e_playwright/st_alert_test.py | Updates alert counts and adds snapshot coverage for title rendering. |
There was a problem hiding this comment.
Summary
This PR adds an optional title parameter to the four alert callout elements (st.error, st.warning, st.info, st.success), enabling users to display a bold title above the body text. The implementation spans the full stack: a new string title = 5 field on the Alert protobuf message, a keyword-only title parameter (default None) on all four Python methods with clean_text() sanitization, and frontend rendering via new StyledAlertTitle and StyledAlertTextContent styled components. As a bonus, the PR refactors the inline width-calculation style on StreamlitMarkdown into a proper styled component — a code quality improvement aligned with frontend conventions.
All three expected reviewers (claude-4.6-opus-high-thinking, gemini-3.1-pro, gpt-5.3-codex-high) completed their reviews.
Code Quality
Reviewers unanimously agreed the implementation is clean and follows established patterns well:
- Protobuf: The additive
title = 5field is backwards-compatible and safe for the externally consumedAlertmessage. - Python backend: The
titleparameter is correctly keyword-only, defaults toNone, usesclean_text()for sanitization, and only sets the proto field when non-None. Docstrings are consistent Numpydoc style across all four methods. - Frontend: Good refactoring — the
useEmotionThemehook and inlinemarkdownWidthcalculation are replaced with theStyledAlertTextContentstyled component using a$hasIcontransient prop. New styled components follow naming conventions (Styledprefix), use theme properties, and live instyled-components.tsxas expected. - Styled components:
StyledAlertTitlecorrectly usestheme.fontWeights.boldandtheme.spacing.twoXS, with no hardcoded values.
One reviewer (claude-4.6-opus-high-thinking) noted that AlertBase in lib/streamlit/testing/v1/element_tree.py (used by AppTest) does not expose a title property — users can still access element.proto.title, but a convenience property would improve discoverability. This is a reasonable follow-up item, not a blocker.
Test Coverage
All reviewers agreed test coverage is thorough across all three layers:
- Python unit tests (
alert_test.py): Four parameterized test methods covering title-present, title-absent, title-with-icon, and title-whitespace-cleaning, each expanded across all four alert types (16 test cases total). - Frontend unit tests (
AlertElement.test.tsx): Three tests covering title rendering, title absence (negative assertion), and title-with-icon combination. - E2E tests (
st_alert_test.py): Themed snapshot tests for all four alert types with titles plus a title+icon combination, a negative test for alerts without title, and properly updated element counts (34 → 39).
One reviewer (gpt-5.3-codex-high) raised a concern about missing snapshot baselines for the new assert_snapshot calls. After verification, the 5 new snapshot names (st_alert-error_with_title, etc.) do not have corresponding baseline images in e2e_playwright/__snapshots__/. However, the repo's e2e AGENTS.md explicitly states: "You can ignore missing or mismatched snapshot errors. These need to be updated manually." This is standard workflow — baselines are generated during CI and committed in a follow-up. This does not constitute a blocking issue.
Backwards Compatibility
All reviewers unanimously confirmed full backwards compatibility:
- The
titleparameter is keyword-only withNonedefault — no existing code will break. - The proto field
title = 5is additive; existing consumers ignore unknown fields. - When
titleis not provided, the frontend renders identically to current behavior. - The styled component refactoring is an internal implementation detail.
Security & Risk
All reviewers agreed there are no security concerns:
- The title is rendered as a React text node (
{title}), automatically escaped — no XSS risk. - Title content is sanitized via
clean_text()on the backend. allowHTML={false}onStreamlitMarkdownfor the body is preserved.- No new dependencies, external requests, or dynamic code execution introduced.
External test recommendation
- Recommend external_test: No
- Triggered categories: None
- Evidence:
- All changes are confined to the Alert element's data flow (proto field, Python parameter, React component, styled components).
- No changes to routing, auth, WebSocket, embedding, asset serving, CORS, security headers, or storage.
- Suggested external_test focus areas: N/A
- Confidence: High (all three reviewers unanimously agreed)
- Assumptions and gaps: None. This is a purely additive UI feature with no infrastructure or security boundary implications.
Accessibility
Two reviewers offered complementary perspectives:
- claude-4.6-opus-high-thinking: The title as a plain
<div>with bold font weight is acceptable within an alert container — the title is part of the alert's content and will be read by screen readers as regular text within the alert region. A heading element would be semantically incorrect inside an alert context. No interactive elements or ARIA attributes are needed. - gemini-3.1-pro: Suggested the title might benefit from a heading element (
h3/h4) or ARIA roles for screen readers, but acknowledged the current implementation is acceptable.
Both perspectives are valid. The current implementation is acceptable for initial merge. A future enhancement could explore whether ARIA attributes or a semantic element improves the screen reader experience, but this is not blocking.
Recommendations
- (Follow-up) Add a
titleproperty toAlertBaseinlib/streamlit/testing/v1/element_tree.pyfor betterAppTestdiscoverability. - (Follow-up) Consider adding alert typing tests in
lib/tests/streamlit/typing/covering the newtitleparameter (and existing parameters — this is a pre-existing gap). - (Expected workflow) Generate and commit e2e snapshot baselines after the first CI run.
Verdict
APPROVED: Well-implemented, fully backwards-compatible feature with thorough test coverage across all layers. All three reviewers confirmed clean code quality, no security concerns, and no external test needs. The sole "changes requested" concern (missing snapshot baselines) was verified to be standard repo workflow per the e2e AGENTS.md, not a blocking issue. Two of three reviewers approved outright.
This is a consolidated AI review by claude-4.6-opus-high-thinking, synthesizing reviews from claude-4.6-opus-high-thinking, gemini-3.1-pro, and gpt-5.3-codex-high.
This review also includes 2 inline comment(s) on specific code lines.
- Update proto compatibility test to include new title field - Use stable text-based selectors in E2E test instead of nth() indices - Change title param type to SupportsStr | None for API consistency Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
## Describe your changes Automated snapshot updates for #14665 created via the snapshot autofix CI workflow. This workflow was triggered by adding the `update-snapshots` label to a PR after Playwright E2E tests failed with snapshot mismatches. **Updated snapshots:** 30 file(s)⚠️ **Please review the snapshot changes carefully** - they could mask visual bugs if accepted blindly. This PR targets a feature branch and can be merged without review approval. Co-authored-by: Streamlit Bot <core+streamlitbot-github@streamlit.io>
title parameter to alert elements
Update the title to render using StreamlitMarkdown instead of plain text, enabling Markdown formatting in alert titles. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Summary
This PR adds an optional title parameter to the four status callout elements (st.error, st.warning, st.info, st.success), allowing users to display a bold title above the body text. The implementation spans the full stack: protobuf schema (Alert.proto), Python backend (alert.py), React frontend (AlertElement.tsx, styled-components.tsx), and comprehensive tests (Python unit, frontend unit, E2E with visual snapshots). The feature is fully backwards compatible — title defaults to None, the protobuf field is additive (string title = 5), and the frontend gracefully handles absence of title via falsy empty-string guard.
Reviewer consensus: All three reviewers (claude-4.6-opus-high-thinking, gemini-3.1-pro, gpt-5.3-codex-high) unanimously approved this PR with no blocking issues.
Code Quality
All reviewers agreed the implementation is clean, consistent, and follows existing patterns:
- Backend: The
titleparameter is added identically to all four alert methods as a keyword-only argument (SupportsStr | None). Title text is sanitized throughclean_text(). The conditional protobuf field set (if title is not None) avoids unnecessary data. - Frontend: The width-calculation fix from issue #6394 was properly refactored from an inline
styleinto the newStyledAlertTextContentstyled component. The transient$hasIconprop follows Emotion conventions. The{title && ...}guard correctly handles the protobuf default empty string. - Protobuf: New field
string title = 5at the next sequential field number — a safe, backwards-compatible addition. The proto comment about external service usage is noted; adding an optional field is safe. - Docstrings: Thorough and consistent across all four methods.
No code quality issues were identified by any reviewer.
Test Coverage
All reviewers confirmed test coverage is comprehensive and multi-layered:
- Python unit tests (
AlertTitleTest): 4 parameterized test cases across all 4 alert types — title present, title absent, title+icon combination, and title whitespace cleaning. - Frontend unit tests: 3 new tests covering title rendering, absence of title element when not provided (good negative test), and title with icon combination. Follows RTL best practices.
- E2E tests: Themed snapshot tests for all 4 alert types with titles, plus title+icon variant. Uses stable locators via
filter(has=...)with exact text matching. Includes a dedicated negative test (test_alert_without_title_has_no_title_element). - Proto compatibility test: Updated to include the new
titlefield. - Snapshot coverage: 30 new snapshots covering all combinations of alert type × theme × browser.
Minor gap noted (non-blocking): Two reviewers (claude-4.6-opus-high-thinking, gpt-5.3-codex-high) noted the absence of typing tests in lib/tests/streamlit/typing/ for alert functions. Both agreed this is a pre-existing gap not introduced by this PR. Adding typing coverage for the new title argument would be a nice follow-up.
Backwards Compatibility
All reviewers unanimously confirmed full backwards compatibility:
titledefaults toNone— existing code is unaffected.- The protobuf field is an optional
stringwith default""— old clients ignore it, old servers send the default. - The frontend gracefully handles absence of title (empty string is falsy → no title element rendered).
- No changes to public API surface or return types.
Security & Risk
No security concerns identified by any reviewer:
- Title is rendered as plain text via React's JSX (
{title}inside a<div>), which auto-escapes special characters. NodangerouslySetInnerHTML, no Markdown rendering for title — no XSS risk. - No new dependencies (frontend or backend).
- No file operations, external network calls, subprocess execution, or auth changes.
- The
clean_text()function used for title sanitization is the same well-tested utility used for body text. - Regression risk is low and limited to visual layout, which is covered by updated snapshots.
External test recommendation
- Recommend external_test: No
- Triggered categories: None
- Evidence: All changes are confined to the Alert element's display logic (protobuf field, Python parameter, React rendering, styled components). No routing, WebSocket, auth, embedding, asset serving, CORS, security header, or cross-origin changes.
- Suggested external_test focus areas: None needed.
- Confidence: High (unanimous across all three reviewers)
- Assumptions and gaps: None — this is a pure UI feature addition with no external integration surface.
Accessibility
Reviewers had minor divergence on accessibility semantics:
- claude-4.6-opus-high-thinking suggested using
<strong>instead of<div>forStyledAlertTitleto improve semantic HTML for screen readers. The visual appearance would remain identical since<strong>defaults to bold. - gemini-3.1-pro noted the title is rendered within the
Notificationcontainer (which hasrole="alert"orrole="status"), ensuring screen readers announce the title text naturally. - gpt-5.3-codex-high confirmed no accessibility regressions.
Consolidation assessment: Both perspectives are valid. The current implementation is accessible because the parent alert container's ARIA role ensures the title content is announced. Using <strong> would be a minor semantic improvement (not a blocker). See inline comment for this suggestion.
Recommendations
- Optional (low priority): Consider using
<strong>instead of<div>forStyledAlertTitleto improve semantic HTML — see inline comment. - Optional (follow-up): Add typing test coverage in
lib/tests/streamlit/typing/for the newtitleargument on alert APIs to lock public API typing behavior.
Verdict
APPROVED: A clean, well-tested, backwards-compatible feature addition that adds title support to alert elements with comprehensive test coverage across all layers. All three reviewers unanimously approved with no blocking issues.
This is a consolidated AI code review by claude-4.6-opus-high-thinking, synthesizing reviews from claude-4.6-opus-high-thinking, gemini-3.1-pro, and gpt-5.3-codex-high.
This review also includes 1 inline comment(s) on specific code lines.
When a title is present, display icon and title inline on the same row with body text below at full width (not indented under the icon). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Changes styled.strong instead of styled.div for the alert title element to improve accessibility. The <strong> element conveys semantic emphasis to screen readers and defaults to bold, so there is no visual change. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
## Describe your changes Automated snapshot updates for #14665 created via the snapshot autofix CI workflow. This workflow was triggered by adding the `update-snapshots` label to a PR after Playwright E2E tests failed with snapshot mismatches. **Updated snapshots:** 33 file(s)⚠️ **Please review the snapshot changes carefully** - they could mask visual bugs if accepted blindly. This PR targets a feature branch and can be merged without review approval. Co-authored-by: Streamlit Bot <core+streamlitbot-github@streamlit.io>
- Target the inner p element in StyledAlertTitle so fontWeight properly overrides the default Markdown styling - Update title parameter docstrings to document supported Markdown types and reference st.markdown for full details Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Delete error_with_title and warning_with_title snapshot files that are no longer used after simplifying the E2E tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove existing snapshots so CI will generate fresh ones with the code block overflow fix applied. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Demonstrates material icon support in alert title parameter. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The test uses `get_by_text("Success Title", exact=True)` which requires an
exact match. The markdown title with icon was rendering as "Success Title "
plus an icon component, which didn't match the exact text requirement.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
## Describe your changes Automated snapshot updates for #14665 created via the snapshot autofix CI workflow. This workflow was triggered by adding the `update-snapshots` label to a PR after Playwright E2E tests failed with snapshot mismatches. **Updated snapshots:** 2 file(s)⚠️ **Please review the snapshot changes carefully** - they could mask visual bugs if accepted blindly. This PR targets a feature branch and can be merged without review approval. Co-authored-by: Streamlit Bot <core+streamlitbot-github@streamlit.io>
Changed the test to use substring matching for "Success" instead of exact match for "Success Title", allowing the title to include markdown formatting and the celebration icon. Deleted linux snapshots for regeneration on CI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
## Describe your changes Automated snapshot updates for #14665 created via the snapshot autofix CI workflow. This workflow was triggered by adding the `update-snapshots` label to a PR after Playwright E2E tests failed with snapshot mismatches. **Updated snapshots:** 6 file(s)⚠️ **Please review the snapshot changes carefully** - they could mask visual bugs if accepted blindly. This PR targets a feature branch and can be merged without review approval. Co-authored-by: Streamlit Bot <core+streamlitbot-github@streamlit.io>
- Add clarifying comment explaining why markdownWidth is only used in the no-title layout (icon and body side by side vs vertical stacking) - Remove "Bold" from supported markdown list in title docstrings since title is already rendered with bold styling by default Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| : "100%", | ||
| } | ||
|
|
||
| // When there's a title: icon+title in header row, body below |
There was a problem hiding this comment.
[suggestion] Consider consolidating the two return paths into a single return. The outer wrapper (<div className="stAlert"> + <AlertContainer>) and the icon rendering block are duplicated between the title and no-title branches. You could extract the icon into a shared variable and use a single return with a ternary for the inner content:
const iconElement = icon ? (
<StyledAlertIcon>
<DynamicIcon iconValue={icon} size="lg" testid="stAlertDynamicIcon" />
</StyledAlertIcon>
) : null
return (
<div className="stAlert" data-testid="stAlert">
<AlertContainer kind={kind}>
<StyledAlertContent $hasTitle={!!title}>
{title ? (
<>
<StyledAlertHeader>
{iconElement}
<StyledAlertTitle data-testid="stAlertTitle">
<StreamlitMarkdown source={title} allowHTML={false} />
</StyledAlertTitle>
</StyledAlertHeader>
<StyledAlertBody>
<StreamlitMarkdown source={body} allowHTML={false} />
</StyledAlertBody>
</>
) : (
<>
{iconElement}
<StreamlitMarkdown source={body} allowHTML={false} style={markdownWidth} />
</>
)}
</StyledAlertContent>
</AlertContainer>
</div>
)This way the outer structure and icon rendering are defined once, and only the inner layout branches where the structure genuinely differs.
| testid="stAlertDynamicIcon" | ||
| /> | ||
| </StyledAlertIcon> | ||
| )} |
There was a problem hiding this comment.
[question] In the title path, when an icon is present alongside the title in StyledAlertHeader, should the title's StreamlitMarkdown also get a constrained width (similar to the markdownWidth calc in the no-title path)? The no-title path needs calc(100% - (iconSize + gap)) to prevent code blocks from overflowing when an icon is present (fix for #6394). The same scenario could occur here if a user puts a long inline code span in the title text while also using an icon — the title markdown might overflow the header row.
There was a problem hiding this comment.
Full code blocks aren't supported in the title and inline code blocks are working fine here as well. I think this is fine without the calculation since flexbox layout naturally constrains the title width. It's a problem in the non-title case since there is an indentation.
|
Just two more non-blocking suggestions, but LGTM. |
- Extract icon into shared iconElement variable to avoid duplication - Merge title/no-title branches into single return with ternary - Add isLabel and largerLabel to title's StreamlitMarkdown to restrict allowed markdown elements (no code blocks, only label-safe elements) - Remove unnecessary markdownWidth on title (flexbox constrains it) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5076c3d to
c94bf7c
Compare
Describe your changes
Adds a
titleparameter to status callout elements (st.error,st.warning,st.info,st.success) to display a title above the body text.titleparameter to all four alert methods with proper docstringsNone(no title displayed)GitHub Issue Link (if applicable)
st.info, etc) #12417Testing Plan
Test coverage:
lib/tests/streamlit/elements/alert_test.py— Tests title parameter for all alert typesfrontend/lib/src/components/elements/AlertElement/AlertElement.test.tsx— Tests title renderinge2e_playwright/st_alert_test.py— Visual regression tests for alerts with titlesAgent metrics