Skip to content
Development
Skill

/emotion-migrate

Migrate Emotion styled-components to Mantine components with style props and CSS modules. Use when converting .styled.tsx files or removing @emotion imports from components.

From plugin
metabase
50k30 skills11 agents23 commands

Claude Code

$ npx -y skills add metabase/metabase --skill emotion-migrate --agent claude-code

SKILL.md

emotion-migrate.SKILL.md
name: emotion-migrate
description: Migrate Emotion styled-components to Mantine components with style props and CSS modules. Use when converting .styled.tsx files or removing @emotion imports from components.

Emotion → Mantine + CSS Modules Migration Skill

Migrate Emotion styled-components (`@emotion/styled`, `@emotion/react`) to Mantine layout components with style props and CSS modules. The goal is zero Emotion imports, zero inline styles, and maximum use of design system tokens.

Priority Order (Strict)

1. **Mantine components + style props** — `Box`, `Flex`, `Stack`, `Group`, `Text`, `Title`, `Card`. This is the DEFAULT. Every CSS property must be checked against style props FIRST. 2. **CSS modules** (`.module.css`) — ONLY for properties that Mantine style props genuinely cannot express: pseudo-selectors (`:hover`, `:focus`, `::before`), `box-shadow`, `border` shorthand, `animation`/`@keyframes`, complex selectors, `cursor`, `pointer-events`, `overflow`, `text-overflow`, `white-space`, `transition`. 3. **Inline styles ONLY for dynamic values** — `style={{ }}` is allowed only for truly dynamic runtime values (e.g., computed widths, positions, data-driven colors). All static styles must use Mantine props or CSS modules.

Mantine-First Decision Gate (CRITICAL)

For EACH styled component, go through every CSS property and ask: "Can this be a Mantine style prop?" If yes → style prop. If no → CSS module. Do NOT dump an entire component into a CSS module just because one property needs it — split them.

**Properties that ARE style props** (use these, not CSS modules):

  • `display` → `display` prop
  • `color` → `c` prop (`c="core-brand"`, `c="text-primary"`)
  • `background-color` → `bg` prop (`bg="background_page-primary"`)
  • `font-size` → `fz` prop (`fz="md"`)
  • `font-weight` → `fw` prop (`fw="bold"`)
  • `line-height` → `lh` prop (`lh="md"`)
  • `text-align` → `ta` prop (`ta="center"`)
  • `padding` (all variants) → `p`, `px`, `py`, `pt`, `pb`, `pl`, `pr`
  • `margin` (all variants) → `m`, `mx`, `my`, `mt`, `mb`, `ml`, `mr`
  • `width` → `w`, `min-width` → `miw`, `max-width` → `maw`
  • `height` → `h`, `min-height` → `mih`, `max-height` → `mah`
  • `flex` → `flex` prop (`flex="0 0 auto"`, `flex={1}`)
  • `gap` → `gap` prop (on Flex/Stack/Group)
  • `align-items` → `align` prop (on Flex/Stack/Group)
  • `justify-content` → `justify` prop (on Flex/Stack/Group)
  • `flex-direction` → `direction` prop (on Flex)
  • `flex-wrap` → `wrap` prop (on Flex)
  • `position` → `pos` prop
  • `top/right/bottom/left` → `top`, `right`, `bottom`, `left` props
  • `opacity` → `opacity` prop

**Properties that NEED CSS modules** (no style prop equivalent):

  • `:hover`, `:focus`, `:active`, `::before`, `::after` (pseudo-selectors)
  • `box-shadow`, `border` (shorthand with color), `outline`
  • `cursor`, `pointer-events`
  • `overflow`, `text-overflow`, `white-space`
  • `animation`, `transition`, `transform`
  • `@media` queries (UNLESS it's simple responsive spacing/sizing — then use responsive syntax: `p={{ base: "md", lg: "xl" }}`)

**Hybrid approach** — when a component needs BOTH, put style props on the Mantine component AND add a CSS module class for the rest:

<Flex
  className={S.root}       /* for :hover, box-shadow, border */
  align="center"            /* style prop */
  gap="sm"                  /* style prop */
  p="md"                    /* style prop */
  bg="background_page-primary"   /* style prop */
>

CSS Module Conventions (Strict)

Class Naming: camelCase

All CSS module class names MUST use **camelCase**. This is the dominant convention across the codebase (~830 camelCase vs ~620 PascalCase classes), used consistently in Mantine UI components, and matches standard CSS module conventions.

/* CORRECT */
.root {
}
.settingsSection {
}
.dragHandle {
}
.closeIcon {
}

/* WRONG — do not use PascalCase or kebab-case */
.ItemRoot {
}
.settings-section {
}

Modifier/state classes also use camelCase:

.selected {
}
.disabled {
}
.interactive {
}
.draggable {
}

No Cascading — Direct Class Assignment

Cascading selectors are **discouraged**. Instead of styling through parent-child relationships, assign a class directly to the element that needs styling.

/* WRONG — cascading/descendant selectors */
.root > input {
}
.root .label {
}
.container > div > span {
}

/* CORRECT — direct class on the target element */
.input {
}
.label {
}
.title {
}

The only acceptable nesting patterns are:

  • **Pseudo-selectors on the same element**: `.item { &:hover { } }`
  • **Modifier composition**: `.item { &.selected { } }`
  • **Hover-reveal patterns** where a parent hover affects a child: `.root:hover .showOnHover { opacity: 1; }` — but only when structurally necessary (the child has no way to know about the parent's hover state)

Import Alias

Always import the CSS module as `S`:

import S from "./ComponentName.module.css";

Step-by-Step Migration Process

Step 1: Read and Understand

Read the `.styled.tsx` file AND every component that imports from it. Understand:

  • Which styled components are used and where
  • Which props drive dynamic styles
  • Which styles are static vs conditional
  • Which styles can map directly to Mantine style props

Step 2: Classify Each Styled Component

For each styled component, apply the Mantine-First Decision Gate above. Then determine the migration target:

| Emotion Pattern | Migration Target | | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `styled.div` with only layout/spacing/color | `Box`, `Flex`, `Stack`, or `

Read more
@metabase
Ships withmetabase

Metabase is the easy, open-source way for everyone in your company to ask questions and learn from data.

50k30 skills11 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
50.3k
Star history of metabase/metabase on GitHub, a chart by star-history.com

Other skills on metabase.

add-malli-schemas

add-malli-schemas

Efficiently add Malli schemas to API endpoints in the Metabase codebase with proper patterns, validation timing, and error…

@metabase@metabaseInstall Skill
add-tracing

add-tracing

Add OpenTelemetry tracing spans to Clojure code following Metabase tracing conventions. Use when instrumenting backend code with…

@metabase@metabaseInstall Skill
api-changelog

api-changelog

Draft or audit the REST API changelog (docs/developers-guide/api-changelog.md) by semantically diffing the checked-in OpenAPI…

@metabase@metabaseInstall Skill
app-db-migrations

app-db-migrations

Add, test, run and roll back application-database (Liquibase) migrations. Use when adding a changeset, changing a table or column…

@metabase@metabaseInstall Skill

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills11d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc12d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react2d252k
@facebook@facebookInstall Skill

Questions about emotion-migrate.

Which coding agents can use emotion-migrate?
emotion-migrate installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.