/ui4
Manually invoked skill for reskinning Payload UI components. Requires Figma URL. Usage: /ui4
$ npx -y skills add payloadcms/payload --skill ui4 --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/ui4
Context preview
The summary Claude sees to decide when to auto-load this skill.
Manually invoked skill for reskinning Payload UI components. Requires Figma URL. Usage: /ui4
SKILL.md
ui4.SKILL.mdname: ui4
description: Manually invoked skill for reskinning Payload UI components. Requires Figma URL. Usage: /ui4
Payload UI Reskin (ui4)
**Figma URL is REQUIRED.** If not provided, ask before proceeding.
---
Process
Step 0: Icon Scan
**Goal:** Identify icon dependencies before starting work.
1. **Scan component files** for icon imports:
grep -E "from.*icons|import.*Icon" packages/ui/src/elements/ComponentName/
2. **List existing icons** in `packages/ui/src/icons/`:
- Each icon has its own folder with `index.tsx` + `index.css`
3. **Compare Figma design** to available icons:
- Does the design use icons not currently in the component?
- Does the design use icons that don't exist yet?
4. **Document findings:**
- **Existing & used:** No action needed
- **Existing but not imported:** Will need to add import
- **Missing from codebase:** Flag for user — need to source/create icon
**Figma Icons Source:**
When updating or creating icons, reference the Figma icon library at:
~/figma/figma/fpl/icons/src/icons/
Icon naming convention: `icon-{size}-{name}.tsx` (e.g., `icon-16-close.tsx`, `icon-24-chevron-down.tsx`)
To find the correct icon:
1. Note the icon name from Figma design (e.g., "close", "chevron-down") 2. Check both 16px and 24px variants if they exist 3. Read the corresponding files and extract the SVG paths for each size
**Icon implementation rules:**
1. **Props:** Icon components MUST accept these props (keep existing props when updating):
type IconProps = {
readonly className?: string
readonly size?: 16 | 24 // Add more sizes as needed
// ... keep any existing component-specific props
}2. **Multi-size support:** Store path data keyed by size:
const paths = {
16: 'M4.854 4.146...', // from icon-16-{name}.tsx
24: 'M6.854 6.146...', // from icon-24-{name}.tsx
}3. **SVG rendering:** Use the size prop to select path and viewBox:
<svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} fill="none">
<path d={paths[size]} fill="currentColor" />
</svg>4. **Payload conventions:**
- Use `fill="currentColor"` instead of `fill="var(--color-icon)"`
- Use `fillRule` and `clipRule` (React camelCase) instead of kebab-case
- Default size should match most common usage (typically 24)
5. **Reference implementation:** See `packages/ui/src/icons/Chevron/index.tsx` for the pattern.
**If icons are missing from Figma source:** Ask user how to proceed before continuing.
---
Step 1: SCSS → CSS Migration
**Goal:** Syntax conversion only. Component must look IDENTICAL after.
1. Read component files: `packages/ui/src/elements/ComponentName/` or `packages/ui/src/fields/ComponentName/` 2. Create `index.css` with converted styles:
- `$var` → `var(--token)`
- Keep CSS nesting with `&` (preferred)
- Remove `@use`/`@import` (tokens are global)
- Inline any mixins
3. Update import: `import './index.scss'` → `import './index.css'` 4. Delete `index.scss` 5. Wrap in `@layer payload-default {}` 6. **Convert legacy `var(--base)` to `--spacer` tokens** (see below) 7. **Check for SCSS-only variables** (see below)
---
SCSS Variable Dependencies
**CRITICAL:** The `packages/ui/src/scss/` folder has been removed. All global tokens now live in `packages/ui/src/css/`. Any CSS variable you use must exist there.
**Before using a variable, verify it exists in the CSS folder:**
grep -r "variable-name" packages/ui/src/css/
**If a variable is only in SCSS:**
1. Check if there's an equivalent in the CSS folder 2. If not, add it to the appropriate CSS file:
- `spacing.css` — spacers, gutters, layout spacing, breakpoints
- `colors.css` — color tokens
- `typography.css` — font tokens
- `radius.css` — border-radius tokens
- `utilities.css` — accessibility, misc utilities
**Common SCSS-only variables to watch for:**
| SCSS Variable | CSS Equivalent / Action | | ----------------------- | ------------------------------------------------ | | `--spacing-view-bottom` | Defined in `spacing.css` | | `--breakpoint-m-width` | Defined in `spacing.css` (1024px) | | `--breakpoint-s-width` | Defined in `spacing.css` (768px) | | `--gutter-h` | Defined in `spacing.css` | | `$breakpoint-m-width` | Use `var(--breakpoint-m-width)` in media queries | | `@include mid-break` | Use `@media (max-width: 1024px)` | | `@include small-break` | Use `@media (max-width: 768px)` |
---
Legacy Token Migration: `var(--base)` → `--spacer`
**What is `--base`?** A legacy spacing token equal to `20px` (1.25rem). It must be replaced with `--spacer-*` tokens.
**Spacer token values:**
| Token | Value | Pixels | | -------------- | ----- | ------ | | `--spacer-0` | 0 | 0px | | `--spacer-1` | 4px | 4px | | `--spacer-2` | 8px | 8px | | `--spacer-2-5` | 12px | 12px | | `--spacer-3` | 16px | 16px | | `--spacer-4` | 24px | 24px | | `--spacer-5` | 32px | 32px | | `--spacer-6` | 40px | 40px |
**Conversion strategy:**
1. **Direct match:** If the result equals a spacer token, use it directly:
/* Before: var(--base) = 20px → closest is --spacer-3 (16px) or --spacer-4 (24px) */
padding: var(--base);
/* After: Choose semantically correct size */
padding: var(--spacer-4); /* if 24px is acceptable */
2. **Calculated values:** When exact pixel value is important, use `calc()`:
/* Before: calc(var(--base) * 0.5) = 10px */
gap: calc(var(--base) * 0.5);
/* After: calc(var(--spacer-1) * 2.5) = 10px */
gap: calc(var(--spacer-1) * 2.5);
3. **ALWAYS round to nearest spacer token.** Never use `calc()` to preserve non-standard pixel values. Ro
Read more
name: ui4 description: Manually invoked skill for reskinning Payload UI components. Requires Figma URL. Usage: /ui4
Payload UI Reskin (ui4)
**Figma URL is REQUIRED.** If not provided, ask before proceeding.
---
Process
Step 0: Icon Scan
**Goal:** Identify icon dependencies before starting work.
1. **Scan component files** for icon imports:
grep -E "from.*icons|import.*Icon" packages/ui/src/elements/ComponentName/
2. **List existing icons** in `packages/ui/src/icons/`:
- Each icon has its own folder with `index.tsx` + `index.css`
3. **Compare Figma design** to available icons:
- Does the design use icons not currently in the component?
- Does the design use icons that don't exist yet?
4. **Document findings:**
- **Existing & used:** No action needed
- **Existing but not imported:** Will need to add import
- **Missing from codebase:** Flag for user — need to source/create icon
**Figma Icons Source:**
When updating or creating icons, reference the Figma icon library at:
~/figma/figma/fpl/icons/src/icons/
Icon naming convention: `icon-{size}-{name}.tsx` (e.g., `icon-16-close.tsx`, `icon-24-chevron-down.tsx`)
To find the correct icon:
1. Note the icon name from Figma design (e.g., "close", "chevron-down") 2. Check both 16px and 24px variants if they exist 3. Read the corresponding files and extract the SVG paths for each size
**Icon implementation rules:**
1. **Props:** Icon components MUST accept these props (keep existing props when updating):
type IconProps = {
readonly className?: string
readonly size?: 16 | 24 // Add more sizes as needed
// ... keep any existing component-specific props
}2. **Multi-size support:** Store path data keyed by size:
const paths = {
16: 'M4.854 4.146...', // from icon-16-{name}.tsx
24: 'M6.854 6.146...', // from icon-24-{name}.tsx
}3. **SVG rendering:** Use the size prop to select path and viewBox:
<svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} fill="none">
<path d={paths[size]} fill="currentColor" />
</svg>4. **Payload conventions:**
- Use `fill="currentColor"` instead of `fill="var(--color-icon)"`
- Use `fillRule` and `clipRule` (React camelCase) instead of kebab-case
- Default size should match most common usage (typically 24)
5. **Reference implementation:** See `packages/ui/src/icons/Chevron/index.tsx` for the pattern.
**If icons are missing from Figma source:** Ask user how to proceed before continuing.
---
Step 1: SCSS → CSS Migration
**Goal:** Syntax conversion only. Component must look IDENTICAL after.
1. Read component files: `packages/ui/src/elements/ComponentName/` or `packages/ui/src/fields/ComponentName/` 2. Create `index.css` with converted styles:
- `$var` → `var(--token)`
- Keep CSS nesting with `&` (preferred)
- Remove `@use`/`@import` (tokens are global)
- Inline any mixins
3. Update import: `import './index.scss'` → `import './index.css'` 4. Delete `index.scss` 5. Wrap in `@layer payload-default {}` 6. **Convert legacy `var(--base)` to `--spacer` tokens** (see below) 7. **Check for SCSS-only variables** (see below)
---
SCSS Variable Dependencies
**CRITICAL:** The `packages/ui/src/scss/` folder has been removed. All global tokens now live in `packages/ui/src/css/`. Any CSS variable you use must exist there.
**Before using a variable, verify it exists in the CSS folder:**
grep -r "variable-name" packages/ui/src/css/
**If a variable is only in SCSS:**
1. Check if there's an equivalent in the CSS folder 2. If not, add it to the appropriate CSS file:
- `spacing.css` — spacers, gutters, layout spacing, breakpoints
- `colors.css` — color tokens
- `typography.css` — font tokens
- `radius.css` — border-radius tokens
- `utilities.css` — accessibility, misc utilities
**Common SCSS-only variables to watch for:**
| SCSS Variable | CSS Equivalent / Action | | ----------------------- | ------------------------------------------------ | | `--spacing-view-bottom` | Defined in `spacing.css` | | `--breakpoint-m-width` | Defined in `spacing.css` (1024px) | | `--breakpoint-s-width` | Defined in `spacing.css` (768px) | | `--gutter-h` | Defined in `spacing.css` | | `$breakpoint-m-width` | Use `var(--breakpoint-m-width)` in media queries | | `@include mid-break` | Use `@media (max-width: 1024px)` | | `@include small-break` | Use `@media (max-width: 768px)` |
---
Legacy Token Migration: `var(--base)` → `--spacer`
**What is `--base`?** A legacy spacing token equal to `20px` (1.25rem). It must be replaced with `--spacer-*` tokens.
**Spacer token values:**
| Token | Value | Pixels | | -------------- | ----- | ------ | | `--spacer-0` | 0 | 0px | | `--spacer-1` | 4px | 4px | | `--spacer-2` | 8px | 8px | | `--spacer-2-5` | 12px | 12px | | `--spacer-3` | 16px | 16px | | `--spacer-4` | 24px | 24px | | `--spacer-5` | 32px | 32px | | `--spacer-6` | 40px | 40px |
**Conversion strategy:**
1. **Direct match:** If the result equals a spacer token, use it directly:
/* Before: var(--base) = 20px → closest is --spacer-3 (16px) or --spacer-4 (24px) */ padding: var(--base); /* After: Choose semantically correct size */ padding: var(--spacer-4); /* if 24px is acceptable */
2. **Calculated values:** When exact pixel value is important, use `calc()`:
/* Before: calc(var(--base) * 0.5) = 10px */ gap: calc(var(--base) * 0.5); /* After: calc(var(--spacer-1) * 2.5) = 10px */ gap: calc(var(--spacer-1) * 2.5);
3. **ALWAYS round to nearest spacer token.** Never use `calc()` to preserve non-standard pixel values. Ro
Payload is the open-source, fullstack Next.js framework, giving you instant backend superpowers. Get a full TypeScript backend and admin panel instantly. Use Payload as a headless CMS or for building powerful applications.
Repo: payloadcms/payload
Other skills on payload.
- /audit-dependencies
Use when fixing dependency vulnerabilities, running pnpm audit, or when the audit-dependencies CI check fails
Open skill - /generate-translations
Use when new translation keys are added to packages to generate new translations strings
Open skill - /triage-ci-flake
Use when CI tests fail on main branch after PR merge, when investigating flaky test failures, or when user provides a PR URL/number to aggregate all failing tests
Open skill - /ui4-convert-tests
Use when UI changes are complete and e2e tests need updating. Analyzes what changed in UI components and systematically finds/fixes affected tests.
Open skill - /ui4-review
Review UI4 CSS migrations for proper token usage. Checks that CSS variables are used instead of hardcoded values.
Open skill - /payload
Use when working with Payload projects (payload.config.ts, collections, fields, hooks, access control, Payload API). Use when debugging validation errors, security issues, relationship queries, transactions, or hook behavior.
Open skill

