Skip to content

Migrate Menu, Layer and Tab to vanilla-extract - #2736

Open
stipsan wants to merge 6 commits into
cursor/vanilla-extract-low-risk-refactors-c941from
cursor/vanilla-extract-third-slice-c941
Open

Migrate Menu, Layer and Tab to vanilla-extract#2736
stipsan wants to merge 6 commits into
cursor/vanilla-extract-low-risk-refactors-c941from
cursor/vanilla-extract-third-slice-c941

Conversation

@stipsan

@stipsan stipsan commented Aug 19, 2026

Copy link
Copy Markdown
Member

Stacked on #2732. Three more low-risk styled-components → vanilla-extract refactors, following the same screening: fully static CSS (no theme or prop interpolation), zero property collisions with runtime-injected styled-components rules (so cascade order between the static stylesheet and runtime styles cannot matter), and each file ends up completely off styled-components. Class name merging uses clsx/lite, introduced on the base PR.

The three refactors

  • Menu (packages/ui/src/core/components/menu/menu.tsx): StyledMenu = styled(Box) with outline: none; overflow: auto becomes <Box className={clsx(menu, className)}>. boxStyle/responsive Box styles never emit outline or overflow unless the overflow prop is passed (Menu never passes it), so there is no collision.
  • Layer (packages/ui/src/core/utils/layer/layer.tsx): styled.div({position: 'relative'}) becomes a plain element with a vanilla-extract class. The as prop previously flowed through the rest-prop spread into styled-components' polymorphism; it is now handled explicitly with the same widening pattern as SrOnly. The two styled(Layer) wrappers keep working: StyledTooltip only adds pointer-events: none (no colliding property), and StyledDialog overrides position through a doubled-specificity && selector that beats the vanilla class regardless of stylesheet order.
  • Tab (packages/ui/src/core/components/tab/tab.tsx): CustomButton = styled(Button) with max-width: 100% becomes <Button className={clsx(tab, className)}>. Nothing in the button primitive sets max-width, so no collision.

Not picked

TabList's styled(Inline) overrides & > div properties that inlineBaseStyle also sets (display, vertical-align) — the values are identical today, but the override relies on styled-components injection order, so it stays behind for now. Same for the previously rejected breadcrumbs ExpandButton and hotkeys Key.

Changeset

One minor changeset, same wording as the second slice: no API changes, but these components now require the @sanity/ui/styles.css import that has been part of the v4 contract since 4.0.0.

Verification

  • pnpm lint (includes tsgolint type checking), pnpm test (all unit tests, including the menu keyboard/spacing tests) and pnpm knip all pass.
  • pnpm --filter @sanity/ui build extracts the three new rule sets into dist/styles.css alongside the second-slice ones.
  • pnpm test:browser passes: 245 tests across 61 story files rendered in headless Chromium with play interactions.
  • Verified computed styles in live Storybook via Playwright:
    • Menu resolves to outline-style: none; overflow: auto with Box's runtime classes still applied (padding intact).
    • Bare Layers (Layer Nested story) resolve to position: relative with their inline z-index (1, 2); the tooltip layer keeps floating-ui's inline position: absolute plus pointer-events: none from StyledTooltip; the dialog layer resolves to position: fixed via the && override — proving overrides in both directions still work.
    • Tab resolves to max-width: 100% with Button's display: inline-flex intact.

Tab story with the Baz tab selected and its panel shown
Dialog centered over a dimmed backdrop, its Layer position fixed
menu_tab_dialog_layer_walkthrough.mp4

To show artifacts inline, enable in settings.

Open in Web Open in Cursor 

cursoragent and others added 4 commits August 19, 2026 16:22
Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
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: b24a936

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:16am
sanity-ui-storybook Ready Ready Preview Aug 21, 2026 9:16am
ui-docs Ready Ready Preview Aug 21, 2026 9:16am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
sanity-ui-workshop Ignored Ignored Aug 21, 2026 9:16am

Request Review

…rsor/vanilla-extract-third-slice-c941

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
…rsor/vanilla-extract-third-slice-c941

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

This PR continues the styled-componentsvanilla-extract migration in @sanity/ui by moving three components’ fully static styles into colocated vanilla-extract modules, ensuring the components no longer depend on styled-components and instead rely on the shared @sanity/ui/styles.css stylesheet.

Changes:

  • Refactored Menu, Layer, and Tab to apply static styles via vanilla-extract classes and clsx/lite class merging.
  • Added new vanilla-extract style modules (menu.css.ts, layer.css.ts, tab.css.ts) to preserve the previous static CSS.
  • Added a minor changeset documenting the migration and reiterating the @sanity/ui/styles.css import requirement.

Reviewed changes

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

Show a summary per file
File Description
packages/ui/src/core/components/menu/menu.tsx Replaces styled(Box) with a vanilla-extract class on Box via clsx.
packages/ui/src/core/components/menu/menu.css.ts Adds static outline and overflow styles as extracted CSS.
packages/ui/src/core/utils/layer/layer.tsx Replaces styled.div with a polymorphic element using a vanilla-extract class and clsx.
packages/ui/src/core/utils/layer/layer.css.ts Adds static position: relative styling as extracted CSS.
packages/ui/src/core/components/tab/tab.tsx Replaces styled(Button) wrapper with Button + vanilla-extract class via clsx.
packages/ui/src/core/components/tab/tab.css.ts Adds static max-width: 100% styling as extracted CSS.
.changeset/vanilla-extract-third-slice.md Declares a minor release and documents the styling contract (@sanity/ui/styles.css).

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

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