Skip to content

New styling for remaining dropdowns (select all 5)#13798

Merged
sfc-gh-dmatthews merged 18 commits intodevelopfrom
02-02-unify-dropdown-styling
Feb 17, 2026
Merged

New styling for remaining dropdowns (select all 5)#13798
sfc-gh-dmatthews merged 18 commits intodevelopfrom
02-02-unify-dropdown-styling

Conversation

@sfc-gh-dmatthews
Copy link
Copy Markdown
Contributor

@sfc-gh-dmatthews sfc-gh-dmatthews commented Feb 3, 2026

Describe your changes

This PR unifies dropdown/popover styling across multiple components to achieve a consistent visual design language. The key changes are:

  • Light/dark mode border behavior: In light mode, borders are hidden (or match the background) and a boxShadow popover effect is shown instead. In dark mode, a visible border is used with no shadow.
  • Border radius updates: Several components switch from theme.radii.default or theme.radii.md to theme.radii.md2 for inner elements, creating more consistent rounding.
  • Spacing adjustments: Menu items, dividers, and header rows have updated padding/margins for tighter, more consistent spacing.
  • popoverMargin: Added to Popover, BaseColorPicker, and TopNavSection for consistent gap between trigger and popover.
  • Scrollbar gutter handling: ColumnVisibilityMenu now uses a CSS custom property (--scrollbar-gutter-size) to adjust divider padding when a scrollbar is present.
  • Background color simplification: Dark mode background for Inner elements changed from secondaryBg to bgColor for consistency.

Screenshot or video (only for visual changes)

GitHub Issue Link (if applicable)

Closes #12956

Testing Plan

  • Explanation of why no additional tests are needed
  • Unit Tests (JS and/or Python)
  • E2E Tests
  • Any manual testing needed?

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 3, 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.

Copy link
Copy Markdown
Contributor Author

sfc-gh-dmatthews commented Feb 3, 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 3, 2026

✅ PR preview is ready!

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

@sfc-gh-dmatthews sfc-gh-dmatthews changed the title st.popover New styling for remaining dropdowns Feb 3, 2026
@sfc-gh-dmatthews sfc-gh-dmatthews changed the title New styling for remaining dropdowns New styling for remaining dropdowns (select all 5) Feb 3, 2026
@sfc-gh-dmatthews sfc-gh-dmatthews added security-assessment-completed change:feature PR contains new feature or enhancement implementation impact:users PR changes affect end users ai-review If applied to PR or issue will run AI review workflow labels Feb 3, 2026
@github-actions github-actions bot removed the ai-review If applied to PR or issue will run AI review workflow label Feb 3, 2026
@sfc-gh-dmatthews sfc-gh-dmatthews changed the base branch from 02-02-date-and-time-styling to graphite-base/13798 February 3, 2026 14:12
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-unify-dropdown-styling branch from 4ea2766 to 7b3dcb4 Compare February 3, 2026 14:15
@sfc-gh-dmatthews sfc-gh-dmatthews changed the base branch from graphite-base/13798 to 02-02-date-and-time-styling February 3, 2026 14:15
@sfc-gh-bnisco sfc-gh-bnisco force-pushed the 02-02-date-and-time-styling branch from 7e95b28 to df804a1 Compare February 3, 2026 17:11
@sfc-gh-bnisco sfc-gh-bnisco force-pushed the 02-02-unify-dropdown-styling branch from 7b3dcb4 to a7296ae Compare February 3, 2026 17:11
@sfc-gh-dmatthews sfc-gh-dmatthews changed the base branch from 02-02-date-and-time-styling to graphite-base/13798 February 3, 2026 17:40
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-unify-dropdown-styling branch from a7296ae to a7d6c2e Compare February 3, 2026 17:40
@sfc-gh-dmatthews sfc-gh-dmatthews changed the base branch from graphite-base/13798 to 02-02-date-and-time-styling February 3, 2026 17:40
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-date-and-time-styling branch from 4a10e1c to 5852cb8 Compare February 3, 2026 18:38
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-unify-dropdown-styling branch 2 times, most recently from 7f125f5 to e1f9edf Compare February 3, 2026 19:42
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-date-and-time-styling branch from 5852cb8 to c228524 Compare February 3, 2026 19:42
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-unify-dropdown-styling branch from e1f9edf to 76d39f9 Compare February 3, 2026 19:57
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-date-and-time-styling branch from c228524 to 29551f0 Compare February 3, 2026 19:57
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-date-and-time-styling branch from fc22122 to 3520051 Compare February 4, 2026 18:18
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-unify-dropdown-styling branch from 6276ac9 to fa2e109 Compare February 4, 2026 19:28
@sfc-gh-dmatthews sfc-gh-dmatthews force-pushed the 02-02-date-and-time-styling branch from 3520051 to f266b5b Compare February 4, 2026 19:28
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 9, 2026

Summary

This PR unifies dropdown/popover styling across multiple components to achieve a consistent visual design language. The key changes are:

  1. Light/dark mode border behavior: In light mode, borders are hidden (or match the background) and a boxShadow popover effect is shown instead. In dark mode, a visible border is used with no shadow.
  2. Border radius updates: Several components switch from theme.radii.default or theme.radii.md to theme.radii.md2 for inner elements, creating more consistent rounding.
  3. Spacing adjustments: Menu items, dividers, and header rows have updated padding/margins for tighter, more consistent spacing.
  4. popoverMargin: Added to Popover, BaseColorPicker, and TopNavSection for consistent gap between trigger and popover.
  5. Scrollbar gutter handling: ColumnVisibilityMenu now uses a CSS custom property (--scrollbar-gutter-size) to adjust divider padding when a scrollbar is present.
  6. Background color simplification: Dark mode background for Inner elements changed from secondaryBg to bgColor for consistency.

The PR touches 9 source files and updates 54 screenshot snapshots across chromium, firefox, and webkit.

Code Quality

The code is well-structured and follows existing patterns. Comments explain the rationale for each styling choice (e.g., "No border in light mode, visible border in dark mode"). A few observations:

  1. Minor inconsistency in Popover.tsx (line 119-126): The borderWidth is now conditionally set to theme.spacing.none (i.e., "0") in light mode, but the padding calculation on lines 123-126 still unconditionally subtracts theme.sizes.borderWidth ("1px"):
              borderWidth: lightBackground
                ? theme.spacing.none
                : theme.sizes.borderWidth,

              paddingRight: `calc(${theme.spacing.twoXL} - ${theme.sizes.borderWidth})`, // 1px to account for border.
              paddingLeft: `calc(${theme.spacing.twoXL} - ${theme.sizes.borderWidth})`,
              paddingBottom: `calc(${theme.spacing.twoXL} - ${theme.sizes.borderWidth})`,
              paddingTop: `calc(${theme.spacing.twoXL} - ${theme.sizes.borderWidth})`,

In dark mode: total = 1px border + (1.5rem - 1px) padding = 1.5rem. Correct.
In light mode: total = 0px border + (1.5rem - 1px) padding = 1.5rem - 1px. Off by 1px.
While 1px is likely not noticeable, the comment "1px to account for border" now only applies in dark mode. The padding should ideally be conditioned on the same lightBackground flag for correctness.

  1. Inconsistent border approach across menus: Two different strategies are used:

    • ColumnVisibilityMenu uses borderColor: bgColor with a constant borderWidth to keep the border invisible in light mode without pixel shifts.
    • FormattingMenu, BaseColorPicker, Popover, and TopNavSection use borderWidth: none in light mode.
    • ColumnMenu uses yet a third approach with boxShadow: "none" on Body and all styling on Inner.

    All three approaches work, but the variation could be confusing for future maintainers. The comments do a good job explaining the rationale.

  2. Style function vs. style object: The PR converts some style: { ... } to style: () => ({ ... }) (e.g., ColumnVisibilityMenu, FormattingMenu). While this works fine with BaseWeb's API, it means a new style object is created on each render. This has negligible performance impact but is worth noting as a pattern choice.

  3. Use of theme.spacing.none for borderWidth: Using theme.spacing.none (which resolves to "0") for a borderWidth property is technically mixing semantic tokens — spacing is meant for layout spacing, not border sizing. While it works, using a literal "0" or 0 might be clearer. However, this appears to be a pre-existing pattern in the codebase, so it's acceptable for consistency.

Test Coverage

  • 54 screenshot snapshots updated across chromium, firefox, and webkit for: popover, navigation top nav, dataframe column menu, visibility menu, formatting menu, and search toolbar. This provides good visual regression coverage.
  • No new unit tests added. This is acceptable since the changes are purely visual/styling and are well-covered by the screenshot tests. The existing unit tests for the affected components (Popover.test.tsx, BaseColorPicker.test.tsx, ColumnMenu.test.tsx, ColumnVisibilityMenu.test.tsx, FormattingMenu.test.tsx) should continue to pass as no behavioral changes were made.
  • No new E2E tests added. The existing E2E tests with updated snapshots adequately cover the visual changes.

Backwards Compatibility

No breaking changes. All changes are internal styling adjustments:

  • No public API changes (no Python or protobuf changes).
  • No behavioral changes to any component.
  • The visual appearance changes are intentional and part of a design system update.
  • Custom themes should work correctly since the changes use theme tokens consistently.

Security & Risk

  • No security concerns: Changes are limited to CSS styling.
  • Low regression risk: The visual changes are well-covered by snapshot tests across three browser engines.
  • Potential minor concern: The ColumnVisibilityMenu now removes maxHeight from the Inner div and moves scrolling to a content div. While the comment explains this is to clip the scrollbar within rounded corners, the 70vh cap on the outer content div ensures the menu doesn't grow unboundedly.

Accessibility

  • No interactive elements were added, removed, or altered.
  • role="menuitem" attributes remain intact.
  • aria-label attributes are preserved.
  • Focus styles and keyboard navigation remain unchanged.
  • The borderRadius changes are purely cosmetic and don't affect assistive technology.
  • Color contrast should be maintained since the changes use existing theme tokens (bgColor, bodyText, borderColor).

Recommendations

  1. Consider fixing the Popover.tsx padding calculation (Popover.tsx lines 123-126): The padding subtraction should account for the conditional border width. Something like:

    const borderWidthValue = lightBackground ? theme.spacing.none : theme.sizes.borderWidth
    // ... then use borderWidthValue in both borderWidth and padding calc
    paddingRight: `calc(${theme.spacing.twoXL} - ${borderWidthValue})`,

    This fixes the 1px discrepancy in light mode and makes the code self-consistent.

  2. Consider documenting the border strategy pattern: Since there are now three approaches used across menus (border=none, border=bgColor, transparent Body + styled Inner), it might help future contributors to have a brief comment or dev doc explaining when to use which approach. This is optional but would improve maintainability.

  3. Minor: In StyledPopoverContent (styled-components.ts line 326), the change from 0 to theme.spacing.none is a good practice for token consistency, but the comment "Match dropdown vertical padding (twoXS top/bottom)" is slightly confusing since the actual vertical padding value is twoXS, not none. The comment is about the vertical padding being twoXS, and the horizontal none is implied. This is fine as-is.

Verdict

APPROVED: This is a well-executed visual styling unification PR. The changes consistently apply a light/dark mode border/shadow pattern across 5+ dropdown components, are backed by comprehensive snapshot tests across 3 browsers, and carry no behavioral or backwards-compatibility risk. The 1px Popover padding discrepancy (recommendation #1) is a minor nit that could be addressed in a follow-up.


This is an automated AI review using opus-4.6-thinking. Please verify the feedback and use your judgment.

Copy link
Copy Markdown
Contributor Author

sfc-gh-dmatthews commented Feb 16, 2026

Merge activity

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 unifies dropdown and popover styling across multiple Streamlit components to achieve a consistent, modern visual design. The changes implement the design patterns established for top navigation dropdowns (issue #12956) and apply them to all dropdown menus, data frame menus, color pickers, and popovers throughout the application.

Changes:

  • Introduced getPopoverContainerStyle utility function for consistent light/dark mode border and shadow behavior across all popovers
  • Updated border radius from theme.radii.default to theme.radii.md2 (0.375rem) for dropdown item highlights
  • Adjusted spacing (padding/margins) across menu components for tighter, more consistent spacing
  • Added popoverMargin prop to Popover, BaseColorPicker, and TopNavSection for consistent gap between trigger and content
  • Implemented CSS custom property pattern for dynamic scrollbar gutter handling in ColumnVisibilityMenu
  • Simplified background colors from secondaryBg to bgColor in dark mode for consistency

Reviewed changes

Copilot reviewed 12 out of 69 changed files in this pull request and generated no comments.

Show a summary per file
File Description
frontend/lib/src/index.ts Exports new getPopoverContainerStyle utility
frontend/lib/src/components/shared/Base/styled-components.ts Not changed in diff, but contains the getPopoverContainerStyle implementation
frontend/lib/src/components/widgets/DataFrame/styled-components.ts Applies getPopoverContainerStyle to search bar, removes hardcoded border radius
frontend/lib/src/components/widgets/DataFrame/menus/styled-components.ts Updates padding/margins, adds md2 radius, implements scrollbar gutter handling via CSS custom property
frontend/lib/src/components/widgets/DataFrame/menus/FormattingMenu.tsx Applies getPopoverContainerStyle, simplifies background color logic
frontend/lib/src/components/widgets/DataFrame/menus/ColumnVisibilityMenu.tsx Adds scrollbar gutter hook, applies styling updates, implements CSS custom property for dynamic scrollbar handling
frontend/lib/src/components/widgets/DataFrame/menus/ColumnMenu.tsx Applies getPopoverContainerStyle, removes redundant styling code
frontend/lib/src/components/shared/BaseColorPicker/BaseColorPicker.tsx Adds popoverMargin prop, applies getPopoverContainerStyle to Body override
frontend/lib/src/components/elements/Popover/Popover.tsx Adds popoverMargin prop, applies getPopoverContainerStyle with radius override for xl corners
frontend/app/src/components/Navigation/styled-components.ts Updates border radius to md2, adjusts margins to match dropdown pattern
frontend/app/src/components/Navigation/TopNavSection.tsx Adds popoverMargin, applies getPopoverContainerStyle, removes redundant styling
e2e_playwright/st_dialog.py Adds width="content" to dataframe for consistent test behavior
e2e_playwright/st_dialog_test.py Changes column menu index from 1 to 2 to account for styling changes affecting positioning
e2e_playwright/snapshots/linux/* Updates screenshots to reflect new visual styling

@sfc-gh-dmatthews
Copy link
Copy Markdown
Contributor Author

sfc-gh-dmatthews commented Feb 17, 2026

@sfc-gh-bnisco I force pushed to get rid of the incorrect merge. This is supposed to be 17 commits from (st.popover a0c6d22 to Update snapshots b20b7ed). Somehow when Graphite failed in the middle, a couple of the commits from the previous branch are showing up here and not properly rebased out. I tried to restack/rebase it, but it kept saying, "we believe [this] is 93 commits long" and it wasn't working like expected trying to point it to a different starting point.

There are a handleful of merge conflicts that popped up from something new in develop while the stack was merging. I've cherry-picked the 17 commits into a clean branch with the correct resolution from the current state of develop: safekeeping branch

So, I can abandon this and make a clean PR if I've made this too much of a mess. Either way, I have the data on safely on that other branch.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update design of dropdown menus to align with top nav

3 participants