Back to UI/UX Design

color-palette

colorpaletteUI/UXdesign systemTailwind CSSfrontendthemingaccessibility
⭐ 860πŸ“„ MITπŸ•’ 2026-06-11Source β†—

Install this skill

npx skills add jezweb/claude-skills

Works across Claude Code, Cursor, Codex, Copilot & Antigravity

The color-palette skill provides a systematic approach for building accessible, balanced color systems using Tailwind v4 syntax. By starting with a single brand hex code, it performs HSL-based calculations to derive an 11-shade scale ranging from 50 to 950. The logic handles the technical nuances of color theory, such as decreasing saturation for lighter tints and maintaining full vibrancy for mid-range values. It explicitly maps these generated shades to semantic UI tokens, ensuring light and dark modes stay consistent and readable. By adhering to WCAG contrast standards, this skill minimizes the need for iterative design adjustments, replacing manual color picking with a repeatable, automated generation process that results in clean, professional theme configurations ready for immediate implementation in web projects.

When to Use This Skill

  • β€’Setting up a new brand design system for a web application
  • β€’Converting a single brand color into a full functional theme
  • β€’Generating dark mode variants for an existing UI color set
  • β€’Auditing text and background color pairs for accessibility

How to Invoke This Skill

Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:

  • β€œGenerate a 11-shade palette for this brand color
  • β€œCreate a Tailwind v4 theme based on my primary hex
  • β€œHelp me build a dark mode semantic mapping for my colors
  • β€œCheck the accessibility of these color pairs
  • β€œConvert this hex color to a full UI scale

Pro Tips

  • πŸ’‘Always start with your primary brand color (shade 500) to ensure the generated palette aligns with your core identity.
  • πŸ’‘Utilize the semantic tokens output to name colors based on their purpose (e.g., `primary`, `background`, `foreground`), rather than just their shade number, for better maintainability.
  • πŸ’‘Cross-reference generated colors with accessibility guidelines (WCAG) for contrast ratios, especially for text and interactive elements.

What this skill does

  • β€’Generates 11-shade scales from a single brand hex
  • β€’Maps semantic tokens for both light and dark modes
  • β€’Applies HSL math for consistent lightness variations
  • β€’Validates WCAG contrast ratios for text and UI elements
  • β€’Outputs valid Tailwind v4 @theme CSS blocks

When not to use it

  • βœ•Projects requiring complex multi-color gradients instead of flat shades
  • βœ•Designs relying on non-standard, non-HSL-derived color blending
  • βœ•Situations where you already have a predefined color palette from a design tool like Figma

Example workflow

  1. Provide the base brand hex code
  2. Execute the conversion of the hex to an 11-shade HSL scale
  3. Apply semantic token mapping for light mode
  4. Generate the inverted dark mode variant set
  5. Verify contrast ratios for primary UI text pairs
  6. Export the final color configuration as a Tailwind @theme block

Prerequisites

  • –A target brand hex color
  • –Tailwind CSS project context

Pitfalls & limitations

  • !Attempting to force vibrant colors into low-contrast states without adjusting saturation
  • !Ignoring the specific lightness thresholds for accessibility at the 50 and 950 shade extremes
  • !Over-saturating light-mode backgrounds which can cause eye strain

FAQ

Why does shade 500 represent the brand color?
Shade 500 is used as the anchor because it provides the most balanced representation of the brand hue's original lightness and saturation, serving as a reliable midpoint.
How should I handle dark mode contrast?
Invert the lightness values while keeping the hue and saturation consistent. Use shades 50-200 for dark mode background surfaces to ensure text remains legible.
Can this scale be adjusted for accessibility?
Yes, if contrast fails, you should select a darker shade, such as 700 or 800, for text elements to meet the 4.5:1 ratio requirement.

How it compares

Doing this manually often leads to inconsistent gaps in lightness and accessibility violations, whereas this skill automates the math to guarantee a balanced, standardized output.

Source & trust

⭐ 860 starsπŸ“„ MITπŸ•’ Updated 2026-06-11
πŸ“„ Full skill instructions β€” original source: jezweb/claude-skills
# Color Palette Generation

**Status**: Production Ready βœ…
**Last Updated**: 2026-01-14
**Standard**: Tailwind v4 @theme syntax

---

## Quick Start

Generate complete palette from brand hex:

// Input: Brand hex
const brandColor = "#0D9488" // Teal-600

// Output: 11-shade scale + semantic tokens + dark mode
primary-50: #F0FDFA (lightest)
primary-500: #14B8A6 (brand)
primary-950: #042F2E (darkest)

background: #FFFFFF
foreground: #0F172A
primary: #14B8A6


Use the reference files to generate shades, map semantics, and check contrast.

---

## Color Scale Overview

### Standard 11-Shade Scale

| Shade | Lightness | Use Case |
|-------|-----------|----------|
| 50 | 97% | Subtle backgrounds |
| 100 | 94% | Hover states |
| 200 | 87% | Borders, dividers |
| 300 | 75% | Disabled states |
| 400 | 62% | Placeholder text |
| 500 | 48% | **Brand color** |
| 600 | 40% | Primary actions |
| 700 | 33% | Hover on primary |
| 800 | 27% | Active states |
| 900 | 20% | Text on light bg |
| 950 | 10% | Darkest accents |

**Key principle**: Shade 500 represents your brand color. Other shades maintain hue/saturation while varying lightness.

---

## Hex to HSL Conversion

Convert brand hex to HSL for shade generation:

// Example: #0D9488 β†’ hsl(174, 84%, 29%)
// H (Hue): 174deg
// S (Saturation): 84%
// L (Lightness): 29%


Generate shades by keeping hue constant, adjusting lightness:
- Lighter shades (50-400): Reduce saturation slightly
- Mid shades (500-600): Full saturation
- Darker shades (700-950): Full saturation

See references/shade-generation.md for conversion formula.

---

## Semantic Token Mapping

Map shade scale to semantic tokens for components:

### Light Mode
--background: white
--foreground: primary-950
--card: white
--card-foreground: primary-900
--muted: primary-50
--muted-foreground: primary-600
--border: primary-200
--primary: primary-600
--primary-foreground: white


### Dark Mode
--background: primary-950
--foreground: primary-50
--card: primary-900
--card-foreground: primary-50
--muted: primary-800
--muted-foreground: primary-400
--border: primary-800
--primary: primary-500
--primary-foreground: white


**Pattern**: Invert lightness while preserving relationships. See references/semantic-mapping.md.

---

## Dark Mode Pattern

Swap light and dark shades:

| Light Mode | Dark Mode |
|------------|-----------|
| 50 (97% L) | 950 (10% L) |
| 100 (94% L) | 900 (20% L) |
| 200 (87% L) | 800 (27% L) |
| 500 (brand) | 500 (brand, slightly brighter) |

**Preserve brand identity**: Keep hue/saturation consistent, only invert lightness.

CSS pattern:
:root {
--background: white;
--foreground: hsl(var(--primary-950));
}

.dark {
--background: hsl(var(--primary-950));
--foreground: hsl(var(--primary-50));
}


---

## Contrast Checking

WCAG minimum ratios:
- **Text (AA)**: 4.5:1 normal, 3:1 large (18px+)
- **UI Elements**: 3:1 (buttons, borders)

Quick check pairs:
- primary-600 text on white background
- white text on primary-600 background
- primary-900 text on primary-50 background

**Formula**:
contrast = (lighter + 0.05) / (darker + 0.05)
// Where lighter/darker are relative luminance values


See references/contrast-checking.md for full formula and fix patterns.

---

## Quick Reference

### Generate Complete Palette
1. Convert brand hex to HSL
2. Generate 11 shades (50-950) by varying lightness
3. Map shades to semantic tokens
4. Create dark mode variants (invert lightness)
5. Check contrast for text pairs

### Tailwind v4 Output
Use @theme directive:
@theme {
--color-primary-50: #F0FDFA;
--color-primary-500: #14B8A6;
--color-primary-950: #042F2E;

--color-background: #FFFFFF;
--color-foreground: var(--color-primary-950);
}


### Common Adjustments
- **Too vibrant at light shades**: Reduce saturation by 10-20%
- **Poor contrast on primary**: Use shade 700+ for text
- **Dark mode too dark**: Use shade 900 instead of 950 for backgrounds
- **Brand color too light/dark**: Adjust to shade 500-600 range

---

## Resources

| File | Purpose |
|------|---------|
| references/shade-generation.md | Hex→HSL conversion, lightness values |
| references/semantic-mapping.md | Token mapping for light/dark modes |
| references/dark-mode-palette.md | Inversion patterns, shade swapping |
| references/contrast-checking.md | WCAG formulas, quick check table |
| templates/tailwind-colors.css | Complete CSS output template |
| rules/color-palette.md | Common mistakes and corrections |

---

## Token Efficiency

**Without skill**: ~8-12k tokens trial-and-error for palette generation
**With skill**: ~3-4k tokens using references
**Savings**: ~65%

**Errors prevented**:
- Poor contrast ratios (accessibility violations)
- Inconsistent shade scales
- Broken dark mode (wrong lightness values)
- Raw Tailwind colors instead of semantic tokens
- Missing foreground pairs for backgrounds

---

## Examples

### Brand Color: Teal (#0D9488)
@theme {
/* Shade scale */
--color-primary-50: #F0FDFA;
--color-primary-100: #CCFBF1;
--color-primary-200: #99F6E4;
--color-primary-300: #5EEAD4;
--color-primary-400: #2DD4BF;
--color-primary-500: #14B8A6;
--color-primary-600: #0D9488;
--color-primary-700: #0F766E;
--color-primary-800: #115E59;
--color-primary-900: #134E4A;
--color-primary-950: #042F2E;

/* Light mode semantics */
--color-background: #FFFFFF;
--color-foreground: var(--color-primary-950);
--color-primary: var(--color-primary-600);
--color-primary-foreground: #FFFFFF;
}

.dark {
/* Dark mode overrides */
--color-background: var(--color-primary-950);
--color-foreground: var(--color-primary-50);
--color-primary: var(--color-primary-500);
}


### Brand Color: Purple (#7C3AED)
@theme {
--color-primary-50: #FAF5FF;
--color-primary-500: #A855F7;
--color-primary-950: #3B0764;

--color-background: #FFFFFF;
--color-foreground: var(--color-primary-950);
--color-primary: var(--color-primary-600);
}


---

**Next Steps**: Use references/shade-generation.md to convert your brand hex to HSL and generate the 11-shade scale.


---

# Color Palette Correction Rules

Common mistakes when generating or using color palettes, and how to fix them.

---

## Never Use Raw Tailwind Colors

Use semantic tokens instead of raw Tailwind color classes.

| If Claude suggests... | Use instead... |
|----------------------|----------------|
| bg-blue-500 | bg-primary |
| text-gray-600 | text-muted-foreground |
| border-slate-200 | border-border |
| bg-green-600 (for success) | Define --color-success semantic token |

**Why**: Raw colors break when switching themes, don't adapt to dark mode, and aren't brand-aligned.

**Fix pattern**:
/* Don't hardcode Tailwind colors */
.button { background: #3B82F6; }

/* Use semantic tokens */
.button { background: hsl(var(--color-primary)); }


---

## Always Pair Background with Foreground

Every background token must have a paired foreground token.

| If Claude suggests... | Use instead... |
|----------------------|----------------|
| --color-card only | --color-card + --color-card-foreground |
| bg-primary with text-secondary | bg-primary with text-primary-foreground |
| Changing background without foreground | Update both in dark mode |

**Why**: Dark mode breaks if foreground doesn't update with background.

**Example failure**:
:root {
--color-card: #FFFFFF;
--color-card-foreground: #1E293B; /* Dark text */
}

.dark {
--color-card: #1E293B; /* Now dark background */
/* BUG: card-foreground still #1E293B - invisible text! */
}


**Fix**:
.dark {
--color-card: #1E293B;
--color-card-foreground: #F1F5F9; /* Light text on dark background */
}


---

## Always Check Contrast for Text on Primary

Primary button text must meet WCAG AA (4.5:1 for normal text).

| If Claude suggests... | Use instead... |
|----------------------|----------------|
| White text on primary-500 (3.9:1) | White text on primary-600 or darker |
| primary-600 text on white (5.7:1) | primary-700+ for AAA (7:1+) |
| Assuming brand color works for text | Calculate contrast ratio first |

**Quick fix**: If primary button fails contrast, use shade 100-200 darker.

/* Fails AA (3.9:1) */
--color-primary: var(--color-primary-500);
--color-primary-foreground: #FFFFFF;

/* Passes AA (5.7:1) */
--color-primary: var(--color-primary-600);
--color-primary-foreground: #FFFFFF;


---

## Always Provide Dark Mode Variants

All color definitions need dark mode overrides.

| If Claude suggests... | Use instead... |
|----------------------|----------------|
| Light mode colors only | Light mode + .dark overrides |
| Same shades for light and dark | Inverted shades (50↔950, 100↔900) |
| Primary-600 in both modes | Primary-600 (light), Primary-500 (dark) |

**Pattern**:
@theme {
/* Light mode */
--color-background: #FFFFFF;
--color-foreground: var(--color-primary-950);
--color-primary: var(--color-primary-600);
}

.dark {
/* Dark mode - inverted */
--color-background: var(--color-primary-950);
--color-foreground: var(--color-primary-50);
--color-primary: var(--color-primary-500); /* Brighter for visibility */
}


---

## Use HSL for Generated Shades

HSL provides better interpolation than RGB/Hex for shade generation.

| If Claude suggests... | Use instead... |
|----------------------|----------------|
| Hex interpolation (manual averaging) | Convert to HSL, vary lightness |
| RGB mixing | HSL with constant hue |
| Random lightness values | Standard scale (97%, 94%, 87%...) |

**Why**: HSL preserves hue and saturation, creating a cohesive scale. RGB mixing shifts hue unpredictably.

**Example**:
// Don't mix hex values
const shade100 = averageHex('#0D9488', '#FFFFFF'); // ❌ Hue shifts

// Use HSL with fixed hue
const brand = { h: 174, s: 84, l: 40 }; // #0D9488
const shade100 = { h: 174, s: 67, l: 94 }; // βœ… Same hue, lighter


---

## Don't Use Pure Black or Pure White

Off-black and off-white look better and support elevation.

| If Claude suggests... | Use instead... |
|----------------------|----------------|
| --color-background: #000000 | --color-background: var(--color-primary-950) |
| --color-foreground: #FFFFFF | --color-foreground: var(--color-primary-50) |
| Pure black for dark mode | Shade 950 (10% lightness) |

**Why**:
- Pure black shows OLED smearing
- Pure white is harsh on eyes
- No room for elevation hierarchy

---

## Generate All 11 Shades

Don't skip shades in the scale - all 11 are needed for flexibility.

| If Claude suggests... | Use instead... |
|----------------------|----------------|
| 5-shade scale (100, 300, 500, 700, 900) | Full 11-shade scale (50-950) |
| Custom lightness values | Standard values (97%, 94%, 87%...) |
| Skipping 50 or 950 | Include extremes for backgrounds/text |

**Why**: UI components need full range:
- 50-300: Backgrounds, hover states
- 400-600: Brand colors, primary actions
- 700-950: Text, dark mode backgrounds

---

## Keep Hue Constant Across Shades

All shades should have the same hue value (H in HSL).

| If Claude suggests... | Use instead... |
|----------------------|----------------|
| Shifting hue for lighter shades | Constant hue, vary lightness only |
| "Warmer" lights, "cooler" darks | Same hue throughout |

**Why**: Hue shifts create disjointed palettes that don't feel like one color family.

**Example**:
/* ❌ Wrong - hue shifts */
--color-primary-50: hsl(180, 70%, 97%); /* Shifted to blue-green */
--color-primary-600: hsl(174, 84%, 40%); /* Original teal */

/* βœ… Correct - constant hue */
--color-primary-50: hsl(174, 67%, 97%); /* Same 174deg hue */
--color-primary-600: hsl(174, 84%, 40%);


---

## Reduce Saturation for Light Shades

Lighter shades (50-200) should have reduced saturation to avoid garish pastels.

| If Claude suggests... | Use instead... |
|----------------------|----------------|
| Full saturation for shade 50 | Reduce by 15-20% |
| Same saturation for all shades | Gradient: less for lights, full for darks |

**Pattern**:
const baseSaturation = 84; // Brand color saturation

// Shade 50 (97% lightness)
const shade50Saturation = baseSaturation * 0.8; // 67%

// Shade 600 (40% lightness)
const shade600Saturation = baseSaturation; // 84% (full)


---

## Don't Override Semantic Tokens in Components

Semantic tokens should be defined globally, not overridden per component.

| If Claude suggests... | Use instead... |
|----------------------|----------------|
| .card { --color-primary: #123456; } | Use a different semantic token |
| Component-specific color overrides | Global semantic tokens |

**Why**: Overrides break theme consistency and make dark mode unpredictable.

**Fix**: If component needs different color, define new semantic token:
@theme {
--color-primary: var(--color-primary-600);
--color-accent: var(--color-accent-500); /* For special components */
}


---

## Test Dark Mode Before Finalizing

Always verify dark mode works before committing colors.

| If Claude suggests... | Use instead... |
|----------------------|----------------|
| Testing light mode only | Test both light and dark modes |
| Assuming inversion works | Manually verify each token pair |

**Checklist**:
- [ ] Toggle dark mode and visually inspect
- [ ] Check text readability (no eye strain)
- [ ] Verify buttons/CTAs stand out
- [ ] Test focus rings are visible
- [ ] Check borders aren't too harsh or invisible
- [ ] Verify contrast ratios (WebAIM tool)

---

## Use Semantic Names, Not Descriptive

Token names should describe purpose, not appearance.

| If Claude suggests... | Use instead... |
|----------------------|----------------|
| --color-light-gray | --color-muted |
| --color-dark-teal | --color-primary |
| --color-bright-blue | --color-accent |

**Why**: Descriptive names break when theme changes (dark mode makes "light-gray" dark).

---

## Don't Mix Color Systems

Use one color system consistently (HSL recommended for Tailwind v4).

| If Claude suggests... | Use instead... |
|----------------------|----------------|
| Mix of hex, RGB, HSL | HSL for all custom colors |
| oklch() for some, hsl() for others | Pick one system |

**Recommendation**: Use HSL for:
- Better human readability
- Easier shade generation
- Tailwind v4 compatibility

**Exception**: Use oklch() if perceptual uniformity is critical (advanced use cases).

---

## Summary of Rules

1. βœ… Use semantic tokens, not raw Tailwind colors
2. βœ… Pair every background with a foreground
3. βœ… Check contrast ratios (4.5:1 for text)
4. βœ… Provide dark mode overrides
5. βœ… Use HSL for shade generation
6. βœ… Avoid pure black/white
7. βœ… Generate all 11 shades (50-950)
8. βœ… Keep hue constant across shades
9. βœ… Reduce saturation for light shades
10. βœ… Test dark mode before finalizing

**Prioritize accessibility and consistency over brand purity.**

How to Use This Skill Unit

Option A: Project-Specific (Recommended)

  1. Click "Download" above
  2. In your project, create the directory: .agent/skills/color-palette/
  3. Save the file as SKILL.md
  4. The agent will automatically discover the skill based on its description.

Option B: Global Installation (All Agents)

Save the file to these locations to make it available across all projects:

  • Claude Code: ~/.claude/skills/jezweb/claude-skills/color-palette/SKILL.md
  • Cursor: ~/.cursor/skills/jezweb/claude-skills/color-palette/SKILL.md
  • Antigravity: ~/.gemini/antigravity/skills/jezweb/claude-skills/color-palette/SKILL.md

πŸš€ Install with CLI:
npx skills add jezweb/claude-skills

Read the Master Guide: Mastering Agent Skills β†’

Recommended Rules

View more rules β†’

Recommended Workflows

View more workflows β†’

Recommended MCP Servers

View more MCP servers β†’

Take It Further

Maximize your productivity with these powerful resources

πŸ“‹

Define Your Standards

Set up coding standards to ensure this workflow produces consistent, high-quality results.

Browse Rules Library
πŸ“–

Master Workflows

Learn how to create custom workflows, use Turbo Mode, and build your automation library.

Complete Guide

How to use this Skill in Claude Code & Cursor

For Claude Code (CLI)

To use this skill in Claude Code, copy the rule content into your project's custom instructions or follow our Add-Skill CLI guide. This ensures Claude follows your standards during every code generation.

For Cursor & Windsurf

For Cursor or Windsurf, individual skills are best used in the "Rules for AI" section. This specific unit helps the agent avoid ui/ux design issues, leading to cleaner, more efficient code.

Why the skill format matters: the standardized Agent Skills format lets your AI agent load detailed instructions only when they are relevant, keeping your prompt clean while improving results.

Source & attribution

This skill is categorized under UI/UX Design and is published by JezWeb, maintained in jezweb/claude-skills.

← Browse All Agent Skills
Sponsored AI assistant. Recommendations may be paid.