Skip to content

[fix] Restore layered vconcat width propagation and add #13974 regression tests#13980

Merged
sfc-gh-bnisco merged 1 commit intodevelopfrom
02-17-_fix_restore_layered_vconcat_width_propagation_and_add_13974_regression_tests
Feb 17, 2026
Merged

[fix] Restore layered vconcat width propagation and add #13974 regression tests#13980
sfc-gh-bnisco merged 1 commit intodevelopfrom
02-17-_fix_restore_layered_vconcat_width_propagation_and_add_13974_regression_tests

Conversation

@sfc-gh-bnisco
Copy link
Copy Markdown
Collaborator

@sfc-gh-bnisco sfc-gh-bnisco commented Feb 17, 2026

Describe your changes

Fixed a bug where layered Altair charts inside vconcat compositions with autosize="fit-x" and width="stretch" weren't rendering properly. The issue was in the useVegaElementPreprocessor where we were skipping setting width on layer children, causing "infinite extent" errors. This change ensures that layer children still receive width so layered + vconcat charts can stretch consistently.

GitHub Issue Link (if applicable)

Fixes #13974

Testing Plan

  • Added a regression test case in the e2e_playwright/st_altair_chart.py file that demonstrates the issue
  • Added a new test in st_altair_chart_test.py to verify the fix works properly
  • Updated the unit test in useVegaElementPreprocessor.test.ts to better test the layer + vconcat case

Contribution License Agreement

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

@snyk-io
Copy link
Copy Markdown
Contributor

snyk-io bot commented Feb 17, 2026

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

github-actions bot commented Feb 17, 2026

✅ PR preview is ready!

Name Link
📦 Wheel file https://core-previews.s3-us-west-2.amazonaws.com/pr-13980/streamlit-1.54.0-py3-none-any.whl
📦 @streamlit/component-v2-lib Download from artifacts
🕹️ Preview app pr-13980.streamlit.app (☁️ Deploy here if not accessible)

Copy link
Copy Markdown
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@sfc-gh-bnisco sfc-gh-bnisco added change:bugfix PR contains bug fix implementation impact:users PR changes affect end users security-assessment-completed labels Feb 17, 2026 — with Graphite App
@sfc-gh-bnisco sfc-gh-bnisco added the ai-review If applied to PR or issue will run AI review workflow label Feb 17, 2026
@github-actions github-actions bot removed the ai-review If applied to PR or issue will run AI review workflow label Feb 17, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Summary

This PR fixes a bug (#13974) where layered Altair charts inside vconcat compositions with autosize="fit-x" and width="stretch" weren't rendering properly. The root cause was in useVegaElementPreprocessor.ts, where vconcat children containing a layer key were being skipped during width propagation. Since layer is an overlay operator (not a concatenation operator), it can safely receive a width value. The fix removes "layer" in child from the skip condition, and adds both unit and E2E regression tests.

Files changed:

  • frontend/lib/src/components/elements/ArrowVegaLiteChart/useVegaElementPreprocessor.ts — core fix
  • frontend/lib/src/components/elements/ArrowVegaLiteChart/useVegaElementPreprocessor.test.ts — updated unit tests
  • e2e_playwright/st_altair_chart.py — added regression scenario
  • e2e_playwright/st_altair_chart_test.py — added regression E2E test

Code Quality

The code change is minimal, well-scoped, and correct. The distinction between layer (overlay) and hconcat/vconcat/concat (concatenation) is semantically sound in Vega-Lite: layer compositions share a spatial area and can accept a unified width, while concatenation operators create separate spatial areas that cannot.

The updated comments in useVegaElementPreprocessor.ts (lines 158-161) clearly explain the rationale for the change, making the intent easy to understand for future maintainers.

Minor note: the child.width = containerWidth assignment unconditionally overwrites any existing width on the child, but this is consistent with the pre-existing behavior for non-composition children and is correct in the useContainerWidth context where the intent is to stretch to the container.

Test Coverage

Unit tests (useVegaElementPreprocessor.test.ts):

  • The old parameterized test case for layer (which expected [undefined, 400] — no width on layer children) was correctly removed.
  • A new standalone test "sets width on vconcat children that contain layer" was added, asserting both the layer child and the sibling child receive width 400. This properly validates the behavioral change.
  • The test follows the project's conventions (uses renderHook, consistent structure with neighboring tests).

E2E tests (st_altair_chart_test.py):

  • A new test test_layered_vconcat_fit_x_regression_renders was added as a regression guard.
  • It verifies the chart is visible, has exactly one graphics-document element, and the rendered canvas/SVG is visible (the bug manifested as a hidden SVG with width=0).
  • The test uses the app fixture (light mode), which is appropriate for a functional regression test.
  • The test includes both positive (visibility, correct count) and implicit negative assertions (a chart with width=0 would fail to_be_visible()).

One observation: the removal of expect(charts.locator("[role='graphics-document']")).to_have_count(NUM_CHARTS) in test_altair_chart_displays_correctly slightly weakens the baseline test. This assertion was likely removed because the vconcat+layer regression chart may produce a different number of graphics-document elements. The per-chart visibility loop still provides adequate coverage, but a comment explaining why this global count check was removed would improve clarity.

Backwards Compatibility

The change is fully backwards compatible:

  • Width propagation to vconcat children only happens when useContainerWidth is true, so charts not using container width are unaffected.
  • Charts that previously worked with layer in vconcat (without useContainerWidth) remain unaffected.
  • Charts that were broken by the original skip logic (issue Altair chart width regression for Layered component inside VConcat #13974) will now render correctly.
  • No public API changes; no protobuf changes.

Security & Risk

No security concerns identified. The change is limited to frontend spec preprocessing logic with no impact on data handling, authentication, or external communication.

Risk is low: the fix is a single-line condition change that aligns layer behavior with how Vega-Lite expects width propagation to work. The existing parameterized tests for hconcat, nested vconcat, and concat confirm that those composition types are still correctly excluded from width propagation.

Accessibility

No accessibility impact. This PR changes chart rendering logic only; no DOM structure, ARIA attributes, keyboard interactions, or focus management are affected.

Recommendations

  1. Consider adding a brief comment in test_altair_chart_displays_correctly explaining why the to_have_count assertion for graphics-document was removed (e.g., "Removed because compound charts like vconcat+layer may contain multiple graphics-document elements"), to prevent someone from re-adding it and causing test failures.

  2. The E2E regression test could optionally include a snapshot assertion (assert_snapshot) for visual regression coverage, though the current visibility-based assertions are sufficient for guarding against the specific width=0 bug.

Verdict

APPROVED: Well-scoped, correct bugfix with appropriate unit and E2E test coverage. The semantic distinction between layer and concatenation operators is sound, and the change is fully backwards compatible.


This is an automated AI review by opus-4.6-thinking.

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 fixes a regression introduced in PR #13423 where layered Altair charts inside vconcat compositions with autosize="fit-x" and width="stretch" stopped rendering. The issue was that the width propagation logic was skipping all composition operators including layer, but layer children need to receive width to render correctly within vertical concatenations.

Changes:

  • Modified the width propagation logic to only skip width on nested concatenation operators (hconcat, vconcat, concat) while allowing layer children to receive width
  • Updated unit tests to reflect the corrected behavior
  • Added an E2E regression test to guard against this specific issue in the future

Reviewed changes

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

File Description
frontend/lib/src/components/elements/ArrowVegaLiteChart/useVegaElementPreprocessor.ts Removed "layer" from the composition operator check, allowing layer children to receive width from their vconcat parent
frontend/lib/src/components/elements/ArrowVegaLiteChart/useVegaElementPreprocessor.test.ts Removed incorrect parametrized test case and added new test verifying layer children receive width
e2e_playwright/st_altair_chart.py Added regression test case with layered vconcat chart using autosize="fit-x" and width="stretch"
e2e_playwright/st_altair_chart_test.py Added dedicated regression test function and updated chart count constants

@sfc-gh-bnisco sfc-gh-bnisco force-pushed the 02-17-_fix_restore_layered_vconcat_width_propagation_and_add_13974_regression_tests branch from c6d9537 to 1f40a79 Compare February 17, 2026 18:53
@sfc-gh-bnisco sfc-gh-bnisco marked this pull request as ready for review February 17, 2026 19:16
@github-actions
Copy link
Copy Markdown
Contributor

Consolidated Code Review

Summary

This PR fixes a rendering regression (issue #13974) where Altair charts containing a layer composition inside a vconcat with autosize="fit-x" and width="stretch" failed to render, producing "infinite extent" errors or a hidden SVG with width=0.

Root cause: PR #13423 (commit 46524be57) introduced a width-propagation skip for all Vega-Lite composition operators (hconcat, vconcat, concat, layer) when iterating vconcat children. However, layer is semantically different from concatenation operators — it overlays multiple marks within the same spatial frame and should receive width. This PR correctly narrows the skip to only true concatenation operators (hconcat, vconcat, concat), removing "layer" in child from the condition.

Changes:

  • useVegaElementPreprocessor.ts: Removed "layer" in child from the skip condition so layer children within vconcat receive containerWidth.
  • useVegaElementPreprocessor.test.ts: Replaced the parameterized test case (which expected layer children to NOT receive width) with a standalone test asserting the corrected behavior.
  • st_altair_chart.py: Added a regression scenario with a layered chart inside vconcat using autosize="fit-x" and width="stretch".
  • st_altair_chart_test.py: Added a new regression test and updated baseline chart verification logic.

Reviewer Agreement

Both reviewers (gpt-5.3-codex-high and opus-4.6-thinking) are in full agreement on all aspects:

Aspect Consensus
Fix correctness Correct and well-scoped
Code quality Clean, minimal, low-risk
Test coverage Strong (unit + E2E)
Backwards compatibility No breaking changes
Security No concerns
Accessibility No impact
Verdict Both APPROVED

No disagreements or conflicts to resolve.

Code Quality

The code change is minimal and well-targeted — a single condition removed from an if statement in useVegaElementPreprocessor.ts. Both reviewers confirmed the change is semantically correct: layer operates differently from concatenation operators in Vega-Lite (it shares the same spatial frame), so setting width on it is valid and expected.

The unit test restructuring is appropriate: the old it.each case for layer (expecting [undefined, 400]) was removed and replaced with a standalone test asserting the opposite — that both vconcat children (including the layer child) receive width 400. This is cleaner since it now asserts the inverse of what the remaining parameterized cases test.

Test Coverage

Unit tests: The new standalone test properly validates that vconcat children containing layer now receive width, while existing parameterized tests continue to verify that hconcat, nested vconcat, and concat children are still skipped. Good positive/negative coverage.

E2E tests: The regression test checks chart visibility, correct graphics-document count, and rendered canvas/svg element visibility — directly guarding against the regression signal of a hidden SVG with width=0. The existing test_altair_chart_displays_correctly was improved by validating each baseline chart individually rather than checking a single global count, which is more precise and resilient.

Backwards Compatibility

No API or protocol changes. This restores the behavior from before PR #13423 specifically for layer children. Charts using other nested composition operators (hconcat, vconcat, concat) inside vconcat are unaffected.

Security & Risk

No security concerns. Regression risk is low: the change is narrowly scoped, covered by both unit and E2E tests, and the existing marginal histogram chart test (which uses vconcat + hconcat) continues to pass.

Accessibility

No accessibility impact — changes are limited to chart spec preprocessing logic and E2E test infrastructure.

Minor Suggestions (Non-blocking)

  1. (Both reviewers): Consider adding a bounding-box assertion in the E2E regression test (e.g., assert non-zero width on the rendered chart) to make the width-related failure signal even more direct.
  2. (opus-4.6-thinking): Consider adding a brief inline comment near REGRESSION_CHART_INDEX in the E2E test to note which chart it references, for future maintainers.

Verdict

APPROVED — Clean, well-scoped bug fix that correctly restores width propagation for layer children in vconcat compositions, with appropriate unit and E2E test coverage. Both reviewers approved unanimously with no blocking issues.


Consolidated review by opus-4.6-thinking.


📋 Review by `gpt-5.3-codex-high`

Summary

This PR fixes a regression in Vega-Lite preprocessing where vconcat children with a top-level layer were incorrectly excluded from width propagation under container width mode, which caused rendering failures for autosize="fit-x" + width="stretch" compositions. It also adds targeted frontend unit coverage and e2e regression coverage for issue #13974.

Code Quality

The implementation is focused and low-risk: useVegaElementPreprocessor now skips width propagation only for nested concatenation operators (hconcat, vconcat, concat) while allowing layered children to receive width. The associated test refactor in useVegaElementPreprocessor.test.ts is clear and improves intent by separating "skip" vs "apply" cases. No maintainability concerns were identified in the changed code paths.

Test Coverage

Coverage is strong for this bug fix:

  • Frontend unit tests now explicitly validate that vconcat children containing layer receive propagated width.
  • Existing unit tests continue to verify skip behavior for nested concatenation children.
  • E2E adds a concrete repro app scenario and a dedicated regression test that validates visibility and render presence for the affected chart.

Together these tests exercise both the preprocessing logic and full-stack rendering behavior for the regression path.

Backwards Compatibility

No API or protocol changes were introduced. The behavioral change is targeted to a previously broken composition case and aligns with expected width="stretch" semantics. Existing charts should remain compatible; the skip behavior for nested concatenations is preserved.

Security & Risk

No security issues identified. Regression risk appears low because:

  • The logic change is narrowly scoped.
  • It is covered by both unit and e2e tests.
  • It restores expected behavior for a specific broken composition without broad architectural changes.

Accessibility

No frontend interaction or semantic UI control changes were introduced in this PR. Accessibility impact is neutral.

Recommendations

  1. Optional hardening: in e2e_playwright/st_altair_chart_test.py, add an explicit non-zero bounding-box assertion for the regression chart render surface (in addition to visibility) to make the width-related failure signal even more direct.

Verdict

APPROVED: The fix is focused, well-tested across unit and e2e layers, and appears safe to merge.


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

📋 Review by `opus-4.6-thinking`

Summary

This PR fixes a rendering bug (issue #13974) where Altair charts containing a layer composition inside a vconcat with autosize="fit-x" and width="stretch" failed to render (producing "infinite extent" errors or a hidden SVG with width=0).

The root cause: commit 46524be57 (PR #13423) introduced a width-propagation skip for all Vega-Lite composition operators (hconcat, vconcat, concat, layer) when iterating vconcat children. However, layer is semantically different from concatenation operators -- it overlays multiple marks within the same spatial frame and should receive width. This PR correctly narrows the skip to only true concatenation operators (hconcat, vconcat, concat).

Changes:

  • useVegaElementPreprocessor.ts: Removed "layer" in child from the skip condition so layer children within vconcat receive containerWidth.
  • useVegaElementPreprocessor.test.ts: Replaced a parameterized test case (which expected layer children to NOT receive width) with a standalone test asserting the corrected behavior.
  • st_altair_chart.py: Added a regression scenario with a layered chart inside vconcat using autosize="fit-x" and width="stretch".
  • st_altair_chart_test.py: Added a new regression test and updated baseline chart verification logic.

Code Quality

The code change is minimal and well-targeted -- a single condition removed from an if statement. The updated comments accurately describe the new behavior and rationale.

The unit test was properly restructured: the old parameterized test case for layer (expecting [undefined, 400]) was removed, and a new standalone test "sets width on vconcat children that contain layer" was added that asserts both vconcat children (including the layer child) receive width 400. This is cleaner than keeping it in the it.each block since it now asserts the opposite of what the other parameterized cases test.

The E2E test modifications are also well done:

  • The existing test_altair_chart_displays_correctly was improved by validating each baseline chart individually (1 graphics-document per chart) rather than checking a single global count across all charts. This is more precise and resilient.
  • The BASELINE_CHARTS / REGRESSION_CHART_INDEX / NUM_CHARTS constants improve readability.

Test Coverage

Unit tests: The new standalone test in useVegaElementPreprocessor.test.ts (line 546-569) properly validates that vconcat children containing layer now receive width, while the existing parameterized tests continue to verify that hconcat, nested vconcat, and concat children are still skipped. This provides good positive/negative coverage.

E2E tests: The test_layered_vconcat_fit_x_regression_renders test checks:

  1. Chart visibility
  2. Exactly 1 graphics-document is rendered
  3. The rendered canvas/svg element is visible (directly guarding against the regression signal of a hidden SVG with width=0)

One minor note: the regression test does not include a snapshot comparison. This is acceptable since the primary concern is whether the chart renders at all (vs. breaking with infinite extent), and snapshot tests can be brittle for charts with randomized data. The test appropriately uses app: Page (light mode only) rather than themed_app since visual theming is not the focus.

Backwards Compatibility

This change restores the behavior from before PR #13423 specifically for layer children, meaning charts with layer inside vconcat will render correctly again. Charts using other nested composition operators (hconcat, vconcat, concat) inside vconcat are unaffected -- they continue to be skipped. No breaking changes for existing users; this is purely a bug fix that restores expected functionality.

Security & Risk

No security concerns. The change is a narrowing of a conditional check in client-side spec preprocessing. Risk is low:

  • The original layer skip was introduced recently (Dec 2025, PR [Fix] Altair charts with vconcat and hconcat  #13423) and the existing test for the marginal histogram chart (index 8, which also uses vconcat + hconcat) continues to pass, confirming no regression from the original fix.
  • layer operates differently from concatenation operators in Vega-Lite -- it shares the same spatial frame, so setting width on it is valid and expected.

Accessibility

No accessibility impact. The changes are limited to chart spec preprocessing logic and E2E test infrastructure. No UI component structure, ARIA attributes, or keyboard interaction patterns were modified.

Recommendations

No blocking issues. Minor suggestions:

  1. Consider adding a brief inline comment near REGRESSION_CHART_INDEX = 9 in the E2E test to note it references the layered vconcat regression chart, for future maintainers scanning the constants.
  2. The regression E2E test could optionally use get_by_text("Regression: Layered vconcat chart") to locate the chart's container more robustly instead of relying on nth(REGRESSION_CHART_INDEX), though this is consistent with the existing test patterns in this file.

Verdict

APPROVED: Clean, well-scoped bug fix that correctly restores width propagation for layer children in vconcat compositions, with appropriate unit and E2E test coverage.


This is an automated AI review by opus-4.6-thinking.

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 👍

@sfc-gh-bnisco sfc-gh-bnisco merged commit b64aa2a into develop Feb 17, 2026
44 checks passed
@sfc-gh-bnisco sfc-gh-bnisco deleted the 02-17-_fix_restore_layered_vconcat_width_propagation_and_add_13974_regression_tests branch February 17, 2026 19:52
lukasmasuch pushed a commit that referenced this pull request Feb 20, 2026
…sion tests (#13980)

## Describe your changes

Fixed a bug where layered Altair charts inside vconcat compositions with
`autosize="fit-x"` and `width="stretch"` weren't rendering properly. The
issue was in the `useVegaElementPreprocessor` where we were skipping
setting width on layer children, causing "infinite extent" errors. This
change ensures that layer children still receive width so layered +
vconcat charts can stretch consistently.

## GitHub Issue Link (if applicable)

Fixes #13974

## Testing Plan

- Added a regression test case in the e2e_playwright/st_altair_chart.py
file that demonstrates the issue
- Added a new test in st_altair_chart_test.py to verify the fix works
properly
- Updated the unit test in useVegaElementPreprocessor.test.ts to better
test the layer + vconcat case

---

**Contribution License Agreement**

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

ndawe commented Mar 4, 2026

FWIW, this improved a vconcat with width='stretch' for me where now the charts are expanding, but they are now extending beyond the width of the container causing it to scroll horizontally. I'm using a sidebar layout.

    st.altair_chart(                                                            
        alt.vconcat(*charts),                                                   
        width='stretch',                                                        
    )

@sfc-gh-bnisco
Copy link
Copy Markdown
Collaborator Author

Thanks for the comment here @ndawe. Can you open up a new issue with clear repro code? Thanks!

@ndawe
Copy link
Copy Markdown

ndawe commented Mar 5, 2026

@sfc-gh-bnisco yes, I'll try to reproduce with a simple example and open an issue here if it seems to be a streamlit regression. Based on the positioning of surrounding elements, I'm also suspecting that I might be dealing with an altair issue.

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

Labels

change:bugfix PR contains bug fix implementation impact:users PR changes affect end users

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Altair chart width regression for Layered component inside VConcat

4 participants