Enforce Emotion (@emotion/styled and @emotion/react) as the only styling library; forbid styled-components usage.
95
97%
Does it follow best practices?
Impact
92%
1.61xAverage score across 4 eval scenarios
Passed
No known issues
Why Emotion, why styled-components stays out, and what would change this rule.
Nx generators are pre-configured for Emotion. nx.json pins the style preset across every generator the workspace uses:
"@nrwl/react": { "application": { "style": "@emotion/styled" }, "component": { "style": "@emotion/styled" }, "library": { "style": "@emotion/styled" } },
"@nrwl/next": { "application": { "style": "@emotion/styled" } }Any nx g component, nx g lib, or nx g app will scaffold an Emotion-based file. Forcing styled-components on new code would require overriding this on every generator invocation.
The full Emotion stack is already wired through Next.js.
@emotion/react@11.11.3 — runtime@emotion/styled@11.8.1 — the styled API@emotion/server@11.4.0 — SSR style extraction (essential for Next.js)@emotion/babel-plugin@11.7.2 — display-name + label generation for debuggingStylingProviders is the project's composed Emotion stack. Located at libs/core/src/components/providers/StylingProviders/, it composes ThemeProvider + WebFontProvider + GlobalStyles in one wrapper. All theming flows through it.
Storybook is wired to Emotion through libs/core/src/config/storybook/decorators/withStyling.js, which uses StylingProviders underneath. Every story decorator goes through this.
styled-components stays in package.jsonstyled-components@5.3.5 is in dependencies for historical reasons — there is legacy code somewhere in the repo that may still depend on it. The presence of the dep is the single biggest reason an LLM will reach for it: lockfile completion is a strong signal that overpowers other context.
The rule applies to new code. Existing imports of styled-components are not in scope for this skill. A separate workflow tile (workflows-migrate-styled-components) would cover any future cleanup pass.
This rule is status: stable. It would only change if:
Neither is on the roadmap. If either becomes true, this skill's status would move to experimental while migration patterns are authored, and would be replaced (not amended) by the new direction.
polished for state mathState-color manipulation (hover/active darken, focus lighten, disabled transparentize) is a small surface that benefits from a focused, tree-shakeable utility. polished is in dependencies (4.2.2), is the canonical choice in Button.component.js, and its API matches the pattern used across the codebase.
chroma-js (2.4.2) is also in dependencies but for a different purpose — palette generation, color-space conversion, contrast checking. It is not used for state math. Don't conflate them.
XxxCSS suffixA css-tagged template literal returned from @emotion/react is interpolatable into any styled.x block. Naming these with a CSS suffix (EmptyButtonCSS, withWhiteBorder-style fragments) makes the type obvious at the import site:
import { EmptyButtonCSS } from '../Button.styles';
// └── PascalCase + CSS suffix tells you: "drop me inside a styled block"Plain const names (emptyButton) lose this signal. The convention is the type-hint.