8.1 The 7 Color Families
Every component color in CocoKits belongs to one of 7 families. Each family represents a distinct user intent:
| Family | Purpose | Example Usage |
|---|---|---|
● neutral | Default, unaccented UI | Dividers, borders, muted backgrounds |
● brand | Primary brand identity | Primary buttons, active states, key CTAs |
● info | Informational / neutral-positive | Info banners, help icons, links |
● success | Positive confirmation | Success toasts, completed states |
● warning | Caution, needs attention | Warning alerts, approaching limits |
● danger | Destructive, error, critical | Delete buttons, error messages, validation |
● contrast | Maximum visual weight | High-contrast text, critical emphasis |
Each family has all 6 roles. That means: 7 families × 6 roles = 42 semantic color tokens (plus structural globals).
8.2 The 6 Color Roles
Inspired by Material Design 3's color role system, adapted for CocoKits:
The "loud" color. Bold, saturated. Used for filled backgrounds or key strokes. This is what most people think of as "the brand color."
Usually white or very dark. Must have high contrast against color. Used for text and icons placed on color backgrounds.
The "quiet" version. Low saturation, tinted. Used for subtle backgrounds (light buttons, chips, soft highlights).
Usually dark in light mode, light in dark mode. Must read well against container. Used for text on soft backgrounds.
Typically the same hue as color but used exclusively for stroke/border contexts. Outline buttons, form field borders when active.
An alpha/transparent version of the family color. Used for box-shadow focus indicators to show keyboard navigation state.
8.3 How Color × Type Stay Independent
This is the most important concept for developers. Color and Type are orthogonal — they never need to know about each other.
/* Step 1: The Color class sets CSS variables */
.cck-button__color--brand {
--cck-color: var(--brand-color);
--cck-on-color: var(--brand-on-color);
--cck-container: var(--brand-container);
--cck-on-container: var(--brand-on-container);
--cck-outline: var(--brand-outline);
--cck-focus: var(--brand-focus);
}
.cck-button__color--danger {
--cck-color: var(--danger-color);
--cck-on-color: var(--danger-on-color);
/* ...same pattern for all 7 families... */
}
/* Step 2: The Type class reads whatever color was set */
.cck-button__type--primary:not(:disabled) {
background-color: var(--cck-color); /* reads color class's variable */
color: var(--cck-on-color);
border-radius: var(--button-radius);
}
.cck-button__type--outline {
background-color: transparent;
color: var(--cck-on-container);
border: 1px solid var(--cck-outline);
}
Adding a new color family requires only one new color class. All existing types automatically work with it.
Adding a new type requires only one new type class. All existing colors automatically work with it.
The two dimensions never need to know about each other.
8.4 Structural vs Color-Family Colors
Every component uses a mix of both. The rule of thumb:
color="brand" to color="danger" on the component, it's a color-family color (lives in Color/Active). If it stays the same, it's a structural color (lives in Structure collection).
| Example | Type | Explanation |
|---|---|---|
| Toggle thumb (always white) | Structural | Never changes with color family |
| Toggle track when unchecked (always gray) | Structural | Fixed regardless of brand/danger |
| Toggle track when checked | Color-family | Purple for brand, red for danger |
| Button disabled bg | Structural | Always the same muted gray |
| Button primary background | Color-family | Changes with color prop |
| Focus rings | Color-family | Brand focus ≠ danger focus |
| Form field default border | Structural | Always neutral, uses semantic global |
| Checkbox background when checked | Color-family | Changes per family |
8.5 Figma Mode Inheritance
Variable modes in Figma cascade from parent frames to children. The nearest ancestor with an explicit mode set always wins.
Wrapper frame — Color/Active = "brand" ← all children default to brand
├── Button instance (no override) ← inherits brand
├── Toggle (Color/Active = "danger") ← overrides to danger
│ └── Track (inherits danger)
└── Checkbox (no override) ← inherits brand from wrapper