Shopify's Polaris team made a call that most design system maintainers eventually face: deprecate the React-specific library and rebuild on web components. The technical rationale is sound — web components are framework-agnostic, which means a single implementation can serve React, Vue, plain JavaScript, or whatever comes next. The migration, by contrast, has been anything but smooth.
One thread in the Shopify developer forums captures the problem precisely. A developer notes they're "still stuck on 2025-07 six months later with no viable path forward," specifically because the web components version removed position: absolute support — a fundamental CSS property — citing "inappropriate use." The response from the community is blunt: merchants paying for Plus-tier checkout extensions can't be told that a platform update made their UI worse. Updates should expand capability, not contract it.
That's not a migration problem. That's a design system that accumulated assumptions it never documented, and is now paying the bill.
The Assumptions You Don't Know You're Making
Every design system built on a specific framework makes bets. React-based systems bet on the component model, the hook lifecycle, and client-side rendering. Those bets are invisible when they're winning. They become visible the moment the framework changes underneath you.
Chris West's retrospective on enterprise eCommerce design systems describes a team that rebuilt their system three times in five years — not because they failed, but because the web outpaced their initial architecture. First iteration: component-focused. Second: semantic tokens. Third: managing micro-frontends across three different rendering contexts. The problem wasn't execution. It was that each architecture encoded assumptions about how components would be consumed, and those assumptions expired.
React Server Components are the current version of this problem. Server Components can't use hooks, can't access browser APIs, can't handle events. A component library built assuming client-side execution — which describes most React design systems built before 2023 — will silently break in a Server Components context. Not with an obvious error, but with subtle failures: a modal that can't manage focus state, a tooltip that can't respond to hover, a form component that can't validate on change.
The framework didn't betray you. You just never wrote down what you were assuming.
What Framework-Agnostic Actually Costs
The appeal of web components as a solution is real. A single implementation that works across frameworks sounds like the right answer to framework dependency. But the Polaris migration reveals the actual tradeoff: framework-agnostic components are harder to build well, and the constraints imposed to achieve portability can strip out behavior that framework-specific implementations provided for free.
// React Polaris — position:absolute worked fine
// because the component owned its rendering context
<Popover
active={active}
activator={activator}
onClose={handleClose}
>
<div style={{ position: 'absolute', top: 0, right: 0 }}>
{/* This just worked */}
</div>
</Popover>
// Web Components Polaris — the shadow DOM boundary
// changes what CSS can reach and from where
// position:absolute support removed in the migration
The shadow DOM boundary that makes web components portable is the same boundary that makes certain CSS patterns harder to support. You're not getting framework-agnosticism for free — you're trading one set of constraints for another. The question is whether the new constraints are ones your consumers can live with.
For Shopify's internal teams, maybe. For third-party developers who built checkout extensions on the old behavior, demonstrably not.
The Actual Problem Is Semantic Debt
Here's what the framework migration surfaces but doesn't cause: most design systems don't document what they mean, only what they render.
A recent analysis of AI-assisted design workflows makes this visible from an unexpected angle. When AI agents consume component libraries, they expose a gap that humans paper over with context: the difference between what a component does and what it means. The semantic choices, token references, accessibility metadata, structural decisions — these are what make a component useful rather than just renderable. Humans bring context to a component. A migration script doesn't.
The same gap that breaks AI-assisted workflows breaks framework migrations. When you move from React Polaris to web component Polaris, the component tree is the easy part. What doesn't transfer automatically is the accumulated understanding of why a component was built the way it was — which constraints were intentional, which were framework artifacts, and which were just someone's preference that calcified into convention.
If you don't have that documented, your migration team will make new decisions where old decisions existed, and your consumers will notice the difference before you do.
The Decision Heuristic
Before you migrate your design system to a new framework or rendering model, run this audit: for each component, can you answer "what would break if this ran in a different execution context?" If the answer is "I'm not sure," that's your migration risk surface — not the component count, not the token count, not the API surface area.
Framework migrations don't create technical debt. They reveal it.
