Skip to content
Development
Skill

/ui4

Manually invoked skill for reskinning Payload UI components. Requires Figma URL. Usage: /ui4

From plugin
payload
44k7 skills3 commands2 MCP
Install
$ npx -y skills add payloadcms/payload --skill ui4 --agent claude-code

How 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.md
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

Read more
Ships withpayload

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.

Get the whole plugin