Systematic migration from hardcoded styles to theme tokens and UI components. Identifies hardcoded Tailwind classes, inline styles, and native HTML elements, then replaces them with theme tokens and Storybook-defined UI components. Ensures theme consistency and component reusability across the codebase.
Scanned 9/8/2026
Install to Claude Code
npx -y skills add mattnigh/skills_collection --skill collection --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Collection?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/mattnigh-collection-d04e79c4)More formats (shields.io, HTML) on the badges page.
---
name: theme-to-component-migration
description: >
Systematic migration from hardcoded styles to theme tokens and UI components.
Identifies hardcoded Tailwind classes, inline styles, and native HTML elements,
then replaces them with theme tokens and Storybook-defined UI components.
Ensures theme consistency and component reusability across the codebase.
instructions: |
You are a Theme Migration Specialist responsible for systematically migrating hardcoded
styles to theme tokens and Storybook-defined UI components.
## Scope
**Focus Areas**:
- Identifying hardcoded Tailwind classes (e.g., bg-blue-500, text-red-600)
- Replacing native HTML elements with UI components (button → Button, input → Input)
- Converting inline styles to theme tokens
- Ensuring theme token consistency
- Validating component availability in Storybook
- **Migrating Storybook stories to use UI components** (*.stories.tsx files)
**Out of Scope**:
- Creating new UI components (use component-fix)
- Modifying theme token definitions (use token-fix)
## Workflow
### 1. Investigation Phase
**A. Analyze Theme System**:
Use Explore agent to understand the theme architecture:
```bash
Task tool with:
subagent_type: "Explore"
description: "Analyze theme system and UI components"
prompt: "Investigate the theme system and UI component library:
1. Theme System:
- Locate theme token definitions (packages/theme/src/styles/)
- Identify available semantic tokens (--primary, --destructive, etc.)
- Find theme token mapping in theme.css
2. UI Component Library:
- List all components in packages/ui/src/components/
- Identify components with Storybook definitions (*.stories.tsx)
- Document available component variants and props
3. Pattern Analysis:
- How are theme tokens currently used?
- What's the pattern for component imports?
- Are there any custom tokens that need to be added?
Provide a structured report with:
- Available theme tokens categorized by purpose
- List of UI components with their props
- Current usage patterns
- Any gaps in component or token coverage"
```
**B. Identify Hardcoded Styles**:
Search for common hardcoded patterns:
```bash
# Search for hardcoded color classes (including Storybook files)
mcp__serena__search_for_pattern
--substring-pattern="(bg|text|border)-(red|blue|green|yellow|gray|purple|pink)-[0-9]+"
--paths-include-glob="**/*.{tsx,jsx}"
# Search for native HTML form elements (including Storybook, excluding UI component library)
mcp__serena__search_for_pattern
--substring-pattern="<(input|textarea|button|select)\\s"
--paths-include-glob="**/*.{tsx,jsx}"
--paths-exclude-glob="packages/ui/src/components/**"
# Search for native HTML elements in Storybook stories specifically
mcp__serena__search_for_pattern
--substring-pattern="<(input|textarea|button|select|div|span)\\s"
--paths-include-glob="**/*.stories.tsx"
# Search for inline styles
mcp__serena__search_for_pattern
--substring-pattern="style=\\{\\{.*?\\}\\}"
--paths-include-glob="**/*.{tsx,jsx}"
```
### 2. Migration Planning
**Create Todo List**:
Based on findings, create a prioritized todo list:
```typescript
TodoWrite with todos:
1. Migrate ContactPage form elements to UI components
2. Replace RootLayout hardcoded colors with theme tokens
3. Update theme-overview.stories badges to use theme tokens
4. Add missing Sidebar tokens to theme
5. Validate with typecheck and build
```
**Prioritization**:
- High: Application code (apps/, features/)
- High: Storybook stories (*.stories.tsx) - should use UI components from @internal/ui
- Medium: Documentation examples
- Low: Test files
- Skip: UI component library source (packages/ui/src/components/*) - already using theme tokens
### 3. Migration Execution
**A. Replace Hardcoded Colors with Theme Tokens**:
```typescript
// Before
className="bg-blue-500 text-white hover:bg-blue-700"
// After
className="bg-primary text-primary-foreground hover:bg-primary-hover"
```
**Mapping Reference**:
- `bg-blue-*` → `bg-info` (informational actions)
- `bg-red-*` → `bg-destructive` (destructive actions)
- `bg-green-*` → `bg-success` (success states)
- `bg-yellow-*` → `bg-warning` (warning states)
- `bg-gray-*` → `bg-muted` (muted backgrounds)
**Implementation**:
```typescript
Edit:
file_path: "apps/react-app/src/layouts/RootLayout.tsx"
old_string: "bg-blue-500"
new_string: "bg-info"
```
**B. Replace Native HTML with UI Components**:
```typescript
// Before
<input
type="email"
className="w-full px-3 py-2 border rounded-md"
value={email}
onChange={handleChange}
/>
// After
import { Input } from "@internal/ui"
<Input
type="email"
value={email}
onChange={handleChange}
/>
```
**Common Replacements**:
- `<input>` → `<Input>` (from @internal/ui)
- `<textarea>` → `<Textarea>` (from @internal/ui)
- `<button>` → `<Button>` (from @internal/ui)
- `<select>` → `<Select>` (from @internal/ui)
- Error/Success divs → `<Alert>` (from @internal/ui)
**Implementation Steps**:
1. Add import statement
2. Replace element with component
3. Remove redundant className props (handled by component)
4. Preserve functional props (value, onChange, etc.)
**D. Migrate Storybook Files (*.stories.tsx)**:
**Special Considerations for Storybook**:
- Storybook stories should demonstrate actual UI components, not native HTML
- Always import components from `@internal/ui`
- Remove all hardcoded styling - let components handle theming
- Ensure story args/controls work with component props
```typescript
// Before - Native HTML with hardcoded styles
export const LoginForm: Story = () => (
<form className="space-y-4">
<div>
<label className="block text-sm font-medium">Email</label>
<input
type="email"
className="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md"
/>
</div>
<button
type="submit"
className="w-full bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700"
>
Sign In
</button>
</form>
)
// After - Using UI components
import { Input, Button, Label } from "@internal/ui"
export const LoginForm: Story = () => (
<form className="space-y-4">
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" placeholder="Enter your email" />
</div>
<Button type="submit" className="w-full">
Sign In
</Button>
</form>
)
```
**Implementation Steps for Storybook**:
1. Identify all native HTML form elements in stories
2. Check which UI components are available in `@internal/ui`
3. Add appropriate imports from `@internal/ui`
4. Replace native elements with UI components
5. Remove all hardcoded color/style classes
6. Test story in Storybook UI to verify appearance
7. Ensure story controls/args still function correctly
**C. Replace Error/Success Messages**:
```typescript
// Before
{error && (
<div className="p-3 text-sm text-red-600 bg-red-50 rounded-md">
{error}
</div>
)}
// After
import { Alert, AlertDescription } from "@internal/ui"
{error && (
<Alert variant="destructive">
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
```
**Alert Variants**:
- `variant="destructive"` (errors)
- `variant="success"` (success messages)
- `variant="warning"` (warnings)
- `variant="info"` (informational)
### 4. Handle Missing Tokens
**A. Identify Missing Tokens**:
If components use tokens that don't exist (e.g., --sidebar):
```bash
mcp__serena__search_for_pattern
--substring-pattern="(bg|text|border|ring)-sidebar"
--relative-path="packages/ui/src/components/sidebar.tsx"
```
**B. Add Tokens to base.css**:
For tokens that won't be auto-generated from YAML:
```typescript
Edit:
file_path: "packages/theme/src/styles/base.css"
old_string: "@layer theme {
:root,
[data-theme-mode=\"light\"],
.theme-base-light {
color-scheme: light;
}"
new_string: "@layer theme {
:root,
[data-theme-mode=\"light\"],
.theme-base-light {
color-scheme: light;
/* Sidebar tokens */
--sidebar: var(--card);
--sidebar-foreground: var(--card-foreground);
--sidebar-border: var(--border);
--sidebar-ring: var(--ring);
--sidebar-accent: var(--accent);
--sidebar-accent-foreground: var(--accent-foreground);
}"
```
**C. Add Tokens to theme.css**:
For Tailwind utility class mapping:
```typescript
Edit:
file_path: "packages/theme/src/styles/theme.css"
old_string: "/* Card Variants */
--color-card-bg: hsl(var(--card-bg));
--color-card-subtle: hsl(var(--card-subtle));"
new_string: "/* Card Variants */
--color-card-bg: hsl(var(--card-bg));
--color-card-subtle: hsl(var(--card-subtle));
/* Sidebar */
--color-sidebar: hsl(var(--sidebar));
--color-sidebar-foreground: hsl(var(--sidebar-foreground));"
```
### 5. Validation
**A. Type Check**:
```bash
pnpm typecheck
```
Fix any TypeScript errors related to:
- Missing component imports
- Incorrect prop types
- Missing props
**B. Format Code**:
```bash
pnpm format:fix
```
**C. Build Validation**:
```bash
pnpm build:prepare
```
Ensure:
- All packages build successfully
- No CSS variable errors
- Theme tokens are properly generated
**D. Contrast Validation**:
Automatically runs during build:
- WCAG AA/AAA compliance
- Component contrast validation
- Token usage validation
### 6. Documentation
**Update Memories**:
If new patterns were established:
```typescript
mcp__serena__write_memory
--memory-name="theme-migration-patterns"
--content="# Theme Migration Patterns
## Completed Migrations
- ContactPage: Migrated to Input, Textarea, Alert components
- RootLayout: Environment ribbon colors → theme tokens
- theme-overview: ContrastBadge → subtle tokens
## Common Patterns
- Form inputs → @internal/ui components
- Error messages → Alert variant=\"destructive\"
- Success messages → Alert variant=\"success\"
- Hardcoded colors → semantic tokens (primary, destructive, etc.)
## Custom Tokens Added
- Sidebar tokens in base.css (not in YAML)"
```
## Common Patterns
### Pattern 1: Form Migration
**Identify**:
- Native `<input>`, `<textarea>`, `<select>` elements
- Hardcoded styling classes
**Replace With**:
- `Input`, `Textarea`, `Select` from @internal/ui
- Remove styling classes (handled by components)
### Pattern 2: Alert Messages
**Identify**:
- `<div>` elements with `text-red-600`, `bg-red-50`
- `<div>` elements with `text-green-600`, `bg-green-50`
**Replace With**:
- `Alert` component with appropriate variant
- `AlertDescription` for message content
### Pattern 3: Color Mapping
**Identify**:
- Environment indicators (development, production)
- State indicators (active, disabled)
- Feedback colors (error, success, warning)
**Replace With**:
- Semantic tokens: `info`, `destructive`, `warning`, `success`
- State tokens: `muted`, `accent`
### Pattern 4: Storybook Demo Colors
**Identify**:
- Hardcoded colors in *.stories.tsx files
- Contrast badges, demo components
**Replace With**:
- Subtle tokens: `subtle-success-bg`, `subtle-warning-bg`
- Maintain light/dark mode compatibility
### Pattern 5: Storybook Native HTML Elements
**Identify**:
- Native HTML elements in Storybook stories (*.stories.tsx)
- `<input>`, `<button>`, `<select>`, `<textarea>` in story examples
- Hardcoded form controls used for demonstration
**Replace With**:
- Use actual UI components from `@internal/ui`
- Import from the same package: `import { Button, Input } from "@internal/ui"`
- Ensures Storybook shows actual production components
**Example**:
```typescript
// Before - Native HTML in Storybook story
const Template: Story = () => (
<div>
<input type="text" placeholder="Enter name" className="px-3 py-2 border" />
<button className="bg-blue-500 text-white px-4 py-2">Submit</button>
</div>
)
// After - Using UI components
import { Input, Button } from "@internal/ui"
const Template: Story = () => (
<div className="flex gap-2">
<Input type="text" placeholder="Enter name" />
<Button>Submit</Button>
</div>
)
```
**Why This Matters for Storybook**:
- Storybook should showcase actual production components
- Native HTML elements don't demonstrate the component library
- Theme tokens only work properly with UI components
- Developers copying from Storybook should get correct patterns
## Output Format
### Migration Report
**1. Analysis Summary**:
```
Files Analyzed: 87
Hardcoded Patterns Found: 4
Issues by Category:
- Native HTML elements: 2 files (ContactPage, ...)
- Hardcoded colors: 2 files (RootLayout, theme-overview)
- Missing tokens: 1 (Sidebar)
```
**2. Changes Made**:
```
ContactPage (packages/features/contact/src/components/ContactPage.tsx):
✓ Replaced <input> with <Input>
✓ Replaced <textarea> with <Textarea>
✓ Replaced error div with <Alert variant="destructive">
✓ Replaced success div with <Alert variant="success">
RootLayout (apps/react-app/src/layouts/RootLayout.tsx):
✓ bg-blue-500 → bg-info
✓ bg-yellow-500 → bg-warning
✓ bg-red-500 → bg-destructive
✓ bg-gray-500 → bg-muted
theme-overview.stories.tsx:
✓ bg-green-100 → bg-subtle-success-bg
✓ text-green-800 → text-success
✓ Removed dark mode hardcoded colors
base.css & theme.css:
✓ Added Sidebar tokens (6 new tokens)
```
**3. Validation Results**:
```
✓ TypeScript: 0 errors
✓ Format: Applied (1 file auto-fixed in features/contact)
✓ Build: All packages built successfully
✓ WCAG Contrast: 19/19 passed
✓ Component Validation: No issues
```
**4. Token Coverage**:
```
Theme Tokens Used:
- Semantic: info, destructive, warning, success, muted
- Subtle: subtle-success-bg, subtle-warning-bg, subtle-destructive-bg
- Components: Input, Textarea, Alert, Button
New Tokens Added:
- sidebar, sidebar-foreground, sidebar-border
- sidebar-ring, sidebar-accent, sidebar-accent-foreground
```
## Error Handling
**Component Not Found**:
- Verify component exists in packages/ui/src/components/
- Check component export in packages/ui/src/index.ts
- Use Glob to find component file
**Token Not Found**:
- Check if token exists in generated-tokens.css
- If missing, add to base.css (for non-YAML tokens)
- Add to theme.css for Tailwind utility mapping
**Build Failures After Migration**:
- Run `pnpm build:prepare` to see specific errors
- Check for missing imports
- Verify token names are correct
- Ensure component props are compatible
**Type Errors**:
- Verify import paths are correct
- Check component prop types match usage
- Add missing required props
## Integration with Other Skills
**Precedes**:
- component-fix: May reveal components needing fixes
- documentation-update: Document new patterns
**Follows**:
- component-analysis: Identifies components to migrate
- accessibility-review: Identifies hardcoded colors
**Always Combine With**:
- build-validation: Validate after all changes
## Usage
**Standalone**:
```bash
/serena -d "Execute theme-to-component-migration skill to replace hardcoded styles with theme tokens"
```
**Targeted**:
```bash
/serena -d "Execute theme-to-component-migration skill for ContactPage form elements"
```
**Complete Migration**:
```bash
/serena -d "Execute theme-to-component-migration skill: analyze entire codebase, replace all hardcoded styles with theme tokens and UI components, add missing tokens, validate builds"
```
**Storybook Specific**:
```bash
/serena -d "Execute theme-to-component-migration skill for all Storybook stories (*.stories.tsx files)"
```
**Storybook + App Code**:
```bash
/serena -d "Execute theme-to-component-migration skill: migrate both Storybook stories and application code to use UI components from @internal/ui"
```
examples:
- input: "Execute theme-to-component-migration skill to migrate ContactPage"
output: "Replaces native input/textarea with UI components, converts error/success divs to Alert components, validates builds, reports 4 changes made"
- input: "Execute theme-to-component-migration skill to fix hardcoded colors in RootLayout"
output: "Maps bg-blue-500→bg-info, bg-red-500→bg-destructive, validates theme consistency, confirms builds pass"
- input: "Execute theme-to-component-migration skill for entire apps/ directory"
output: "Scans all app files, identifies 12 hardcoded patterns, migrates to theme tokens and components, adds missing tokens, validates builds, generates migration report"
- input: "Execute theme-to-component-migration skill for all Storybook stories"
output: "Scans *.stories.tsx files, identifies 8 files using native HTML elements, replaces with @internal/ui components (Input, Button, Select, Textarea), removes hardcoded styles, validates Storybook builds, reports 24 changes made"
- input: "Execute theme-to-component-migration skill for theme-overview.stories.tsx"
output: "Replaces hardcoded bg-green-100→bg-subtle-success-bg, text-green-800→text-success, removes dark mode inline colors, validates contrast, confirms builds pass"
model: claude-sonnet-4-5-20250929
---
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!