Skip to content

Migrate MenuDivider, VirtualList and the toast viewport to vanilla-extract - #2732

Open
stipsan wants to merge 8 commits into
mainfrom
cursor/vanilla-extract-low-risk-refactors-c941
Open

Migrate MenuDivider, VirtualList and the toast viewport to vanilla-extract#2732
stipsan wants to merge 8 commits into
mainfrom
cursor/vanilla-extract-low-risk-refactors-c941

Conversation

@stipsan

@stipsan stipsan commented Aug 19, 2026

Copy link
Copy Markdown
Member

Continues the styled-components → vanilla-extract migration started in #2523 ("more components follow in future 4.x minors", per the 4.0.0 release notes) with three low-risk refactors. Each one moves fully static CSS — no theme or prop interpolation — into a colocated .css.ts module extracted into @sanity/ui/styles.css, and removes the styled-components import from its file entirely.

The three refactors

  • MenuDivider (packages/ui/src/core/components/menu/menuDivider.tsx): the static styled.hr becomes a plain <hr> with a vanilla-extract class. The polymorphic as support and public MenuDividerProps<E> type are preserved using the same component-plus-cast pattern as KBD and SrOnly, and a consumer-provided className is still merged.
  • VirtualList (packages/ui/src/core/utils/virtualList/virtualList.tsx): the two static styled.divs (position: relative root, absolutely positioned item wrapper) become vanilla-extract classes. The as polymorphism, rest-prop spreading (so as={Stack} keeps receiving Stack props), inline top/height styles, and className merging are preserved.
  • Toast viewport (packages/ui/src/core/components/toast/toastLayer.tsx): StyledLayer = styled(Grid) becomes <Grid as="ul" className={toastLayer}>. as="ul" is equivalent to the previous forwardedAs="ul", and the inline zIndex from useLayer() is unchanged.

Why these three are low-risk

Candidates were screened for cascade-order safety: the static stylesheet loads before styled-components' runtime-injected styles, so a vanilla-extract class must never need to override a styled-components rule of equal specificity. All three picks have zero property collisions with the runtime styles that remain on their elements (boxStyle/grid styles emit none of the properties the toast viewport sets; the other two style plain DOM elements). Rejected for exactly that reason: breadcrumbs' ExpandButton (margin: -4px must beat Button's runtime margin: 0) and hotkeys' Key (same-specificity display override of KBD).

Changeset

One minor changeset, following the 4.0.0 wording: no API changes, but these components now render unstyled unless the app imports @sanity/ui/styles.css once (required since 4.0.0).

Verification

  • pnpm lint (includes tsgolint type checking), pnpm test (106 unit tests, including menu and toast tests) and pnpm knip all pass.
  • pnpm --filter @sanity/ui build extracts all three rule sets into dist/styles.css with declarations identical to the removed styled-components CSS.
  • pnpm test:browser passes: 245 tests across 61 story files, rendering every story (Menu, MenuButton, MenuItem, Toast, VirtualList included) in headless Chromium with play interactions.
  • Verified computed styles in a live Storybook via Playwright: the divider resolves to height: 1px; background-color: rgb(42, 45, 63); the toast viewport <ul> resolves to position: fixed; right: 0; bottom: 0; display: grid; list-style: none; pointer-events: none; max-width: 420px, and two distinct-id toasts stack with the expected 12px grid gap; the VirtualList root/items resolve to relative/absolute positioning.

Menu with the 1px hairline divider between Inspect and the submenu item
Two toasts stacked in the bottom-right toast viewport
VirtualList scrolled to items 22-36 with even spacing
menu_divider_toast_viewport_virtual_list_walkthrough.mp4

To show artifacts inline, enable in settings.

Open in Web Open in Cursor 

cursoragent and others added 4 commits August 19, 2026 00:11
…xtract

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
…xtract

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
…nilla-extract

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
@changeset-bot

changeset-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c643c51

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@sanity/ui Minor
@sanity/themer Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Aug 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
icons Ready Ready Preview Aug 21, 2026 9:15am
sanity-ui-storybook Ready Ready Preview Aug 21, 2026 9:15am
ui-docs Ready Ready Preview Aug 21, 2026 9:15am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
sanity-ui-workshop Ignored Ignored Aug 21, 2026 9:15am

Request Review

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Migrates three static style blocks (MenuDivider, VirtualList wrapper/item wrapper, and the Toast viewport container) from styled-components to vanilla-extract, continuing the repo’s incremental extraction of static CSS into @sanity/ui/styles.css.

Changes:

  • Replaces styled.* wrappers in VirtualList with vanilla-extract classes and preserves polymorphic as, ref wiring, and className merging.
  • Replaces the toast viewport styled(Grid) wrapper with a toastLayer vanilla-extract class applied directly to Grid as="ul".
  • Replaces styled.hr MenuDivider with a plain polymorphic component applying a vanilla-extract menuDivider class, and adds a changeset documenting the requirement to import @sanity/ui/styles.css.

Reviewed changes

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

Show a summary per file
File Description
packages/ui/src/core/utils/virtualList/virtualList.tsx Removes styled-components wrappers and applies vanilla-extract classes to the polymorphic root and items.
packages/ui/src/core/utils/virtualList/virtualList.css.ts Adds extracted static positioning styles for the VirtualList root and item wrapper.
packages/ui/src/core/components/toast/toastLayer.tsx Removes styled(Grid) wrapper and applies a vanilla-extract class to the Grid toast viewport rendered as <ul>.
packages/ui/src/core/components/toast/toastLayer.css.ts Adds extracted static layout/positioning styles for the toast viewport container.
packages/ui/src/core/components/menu/menuDivider.tsx Replaces styled.hr with a polymorphic component that applies a vanilla-extract class and preserves className merging.
packages/ui/src/core/components/menu/menuDivider.ts Removes the previous styled-components implementation of MenuDivider.
packages/ui/src/core/components/menu/menuDivider.css.ts Adds extracted static divider styles (hairline, background var, margin reset).
.changeset/vanilla-extract-second-slice.md Adds a minor changeset documenting the additional components now depending on @sanity/ui/styles.css.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

…rings

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file
Suppressed comments (1)

pnpm-lock.yaml:11877

  • pnpm-lock now resolves @sanity/vision's @sanity/ui dependency to the published @sanity/ui@4.0.4 instead of the workspace link:packages/ui. Since the repo also depends on the workspace @sanity/ui (e.g. apps/studio), this can lead to two separate @sanity/ui instances in a single app (which is especially risky if contexts/providers are involved) and can make local UI changes not exercised through @sanity/vision. Consider adjusting pnpm workspace resolution (or pinning/overriding) so @sanity/vision uses the workspace @sanity/ui during development/CI, or explain why pulling @sanity/ui@4.0.4 here is expected.

…event)

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
…t-low-risk-refactors-c941

# Conflicts:
#	pnpm-lock.yaml

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file
Suppressed comments (1)

pnpm-lock.yaml:667

  • This lockfile update looks broader than what’s needed for adding clsx to packages/ui (e.g. it also upgrades @module-federation/vite at pnpm-lock.yaml:2487 and @testing-library/user-event at pnpm-lock.yaml:4416, plus several @sanity/* versions like pnpm-lock.yaml:3905). If these upgrades aren’t intentional, consider regenerating pnpm-lock.yaml to keep the diff scoped to the clsx addition; otherwise, please call out the dependency bumps explicitly in the PR description so they’re reviewed as part of scope.

…t-low-risk-refactors-c941

# Conflicts:
#	pnpm-lock.yaml

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants