Maple
⌘K
DOCUMENTATIONv2.0.17

Color System

Maple's color system uses the OKLCH color space to resolve, manipulate, and generate colors entirely at runtime—no build step, no predefined palettes.

Color Resolution

When you write a color utility like c-primary or bgc-accent, Maple resolves the value through a multi-layer CSS variable fallback chain inside the OKLCH color space. This is the generated CSS for a single color utility:

.c-primary {
  color: oklch(
    from var(--c-primary, var(--color-primary, var(--primary, primary)))
      calc(l * var(--c-primary-l-scale, var(--primary-l-scale, var(--c-l-scale, var(--l-scale, 1)))))
      calc(c * var(--c-primary-c-scale, var(--primary-c-scale, var(--c-c-scale, var(--c-scale, 1)))))
      calc(h + var(--c-primary-h-rotate, var(--primary-h-rotate, var(--c-h-rotate, var(--h-rotate, 0))))) /
      alpha
  );
}

This single rule encodes the complete resolution, manipulation, and fallback logic. Let's break it down.

Variable Fallback Chain

The base color value is resolved through a four-step fallback chain. To make the rule produce a valid color, at least one of the following must be defined:

  1. Property-Specific: --c-primary. The property shorthand (c for color) is combined with the value name. For example, bgc-primary first looks for --bgc-primary.
  2. Type-Specific: --color-primary. The first fallback uses the property type. All color properties (color, background-color, border-color, etc.) share the --color-* namespace.
  3. Value-Specific: --primary. The second fallback is the bare value name as a CSS variable.
  4. Literal: primary. The final fallback is the raw string. If it's a valid CSS named color (red, cornflowerblue, silver, etc.), it works out of the box. Invalid names are silently ignored.
Example: Defining a primary color

<!-- Define a single base color -->
<div class="--primary=oklch(0.55_0.25_260)">

  <!-- All of these resolve through the fallback chain -->
  <div class="c-primary">Text uses --primary</div>
  <div class="bgc-primary">Background uses --primary</div>
  <div class="brc-primary">Border uses --primary</div>

  <!-- Override just the background color -->
  <div class="--bgc-primary=oklch(0.9_0.05_260) bgc-primary">
    Background uses --bgc-primary, ignoring --primary
  </div>

</div>
  

Named CSS Colors

Because the literal fallback accepts any CSS named color, classes like c-coral, bgc-teal, and brc-slateblue work without defining any variables. They flow through the same OKLCH pipeline and gain automatic lightness, chroma, and hue controls—see the native palette for ready to use colors.

coral
teal
slateblue

<div>
  <div class="bgc-coral">coral</div>
  <div class="bgc-teal">teal</div>
  <div class="bgc-slateblue">slateblue</div>
</div>
  

Tones

You can generate a wide range of tones from any base color by appending a numeric suffix -{number} to the color name. The tone range spans from 50 (lightest) to 950 (darkest). The calculation is adaptive—it factors in the base color's actual lightness to ensure visually consistent results across different colors:

  • Low tones (e.g. 100–200): Always produce light shades, regardless of the base color's lightness.
  • High tones (e.g. 800–900): Always produce dark shades, regardless of the base color's lightness.
Class
Effect
Logic
c-blue-100
Tint

Light shade — high lightness.

c-blue-500
Mid

Normalized toward mid-lightness.
Not the same as c-blue. See Adaptive Tone Normalization section below.

c-blue-900
Shade

Dark shade — low lightness.

Even though the example below illustrates stepped shades, any number between 50 and 950 is valid—c-primary-51 and c-primary-949 both work. The mathematics is continuous, not stepped.

50
100
200
300
400
500
600
700
800
900
950

<div class="--primary=oklch(0.55_0.25_260)">
  <div class="bgc-primary-50"></div>
  <div class="bgc-primary-100"></div>
  <div class="bgc-primary-200"></div>
  <div class="bgc-primary-300"></div>
  <div class="bgc-primary-400"></div>
  <div class="bgc-primary-500"></div>
  <div class="bgc-primary-600"></div>
  <div class="bgc-primary-700"></div>
  <div class="bgc-primary-800"></div>
  <div class="bgc-primary-900"></div>
  <div class="bgc-primary-950"></div>
</div>
  

Adaptive Tone Normalization

The tone formula compensates for the base color's actual lightness. A dark base color receives a stronger lightening push at low tones, while a light base color receives less. This means c-red-200 and c-skyblue-200 will land in a similar lightness range even though their base lightness values are very different.

As a direct result of this normalization, the 500 tone represents a mathematically aligned midpoint, rather than your exact starting color. For example, c-navy (no tone) uses the raw base color as-is, while c-navy-500 applies the adaptive formula—they are not equivalent.

navy
Raw base color
vs
navy-500
Adaptive mid-tone

<div class="c-white">
  <div class="bgc-navy">Raw base color</div>
  <div class="bgc-navy-500">Adaptive mid-tone</div>
</div>
  

Transparency

Append /{number} to set the alpha channel. Values range from 0 (fully transparent) to 100 (fully opaque):


<!-- 50% opacity -->
<div class="bgc-primary/50">Semi-transparent background</div>

<!-- 20% opacity -->
<div class="c-primary/20">Faded text</div>

<!-- Combined: tone 232 at 68% opacity -->
<div class="bgc-primary-232/68">Light tone, partial transparency</div>
  
20
40
60
80
100

<div class="--primary=oklch(0.55_0.25_260)">
  <div class="bgc-primary-500/20"></div>
  <div class="bgc-primary-500/40"></div>
  <div class="bgc-primary-500/60"></div>
  <div class="bgc-primary-500/80"></div>
  <div class="bgc-primary-500/100"></div>
</div>
  
Pro Tip
Although any number is valid for tones and transparency, it is recommended to use numbers divisible by 5 or 10 to keep your design system consistent and organized.

Color Manipulation

Beyond tones and transparency, Maple gives you fine-grained control over lightness, chroma, and hue via CSS variables. Each variable follows its own fallback chain for maximum flexibility:

Variable
Effect
Default
--l-scale
Scale lightness (multiplicative). Values > 1 make colors lighter, < 1 make them darker.
1
--l-shift
Scale tone shift intensity. Controls how strongly tones move toward white or black. Negative values invert the direction.
1
--c-scale
Scale chroma/saturation. 0 = fully desaturated (grayscale), 1 = base saturation, > 1 = more vivid.
1
--h-rotate
Shift the hue angle in degrees. Positive values rotate clockwise, negative values counter-clockwise.
0
Try the Color Playground
Want to see exactly how these tuning variables affect the generated tones? Jump into the interactive Native Palette to adjust the global sliders and test these concepts on the fly.

Manipulation Fallback Chain

Each manipulation variable follows a four-level fallback chain. To override a value, you can define the following variables (using --l-scale and c-primary as an example):

  1. Property + Value: --c-primary-l-scale. The most specific level. It only affects c-primary. Other color properties using the primary name (like bgc-primary) are not affected.
  2. Value-Specific: --primary-l-scale. Affects all properties using the primary color name.
  3. Property-Specific: --c-l-scale. Affects text color property, regardless of color name.
  4. Global: --l-scale. The final fallback. Affects all color properties across all color names.
Example: Scoped manipulation

<!-- Global lightness scaling -->
<div class="
  --l-scale=1.2 
  --primary=oklch(0.55_0.25_260) 
  --secondary=oklch(0.8_0.05_240)
">

  <!-- Affects all colors in this scope -->
  <div class="bgc-secondary c-primary">
    Primary and secondary are both 20% lighter
  </div>

  <!-- Override for just primary color's lightness -->
  <div class="--primary-l-scale=0.8">
    <div class="bgc-secondary c-primary">
      Primary is now 20% darker,
      Secondary is still 20% lighter
    </div>
  </div>

</div>
  

The same four-level structure applies identically to --l-shift, --c-scale, and --h-rotate.

Global Curve Controls

When tone variations are used (e.g., c-primary-200), two additional global variables control the behavior of the tone curve:

Variable
Effect
Default
--l-edge-shift
Controls the dampening curve of lightness scaling toward extremes. Lower values flatten the curve near white and black.
0.5
--c-curve
Controls the chroma reduction for extreme tones. Higher values desaturate tones near 50 and 950 more aggressively.
0.5

Fallback Reference

The list below serves as a complete reference for every fallback chain. Each category expands into the four resolution levels, from most specific (1) to global (4):

  1. Base Color
    1. --c-primary(Property + Value)
    2. --color-primary(Type + Specific)
    3. --primary(Global)
    4. primary(Value as Literal string)
  2. Lightness Scale
    1. --c-primary-l-scale(Property + Value)
    2. --primary-l-scale(Value Specific)
    3. --c-l-scale(Property Specific)
    4. --l-scale(Global)
  3. Lightness Shift
    1. --c-primary-l-shift(Property + Value)
    2. --primary-l-shift(Value Specific)
    3. --c-l-shift(Property Specific)
    4. --l-shift(Global)
  4. Chroma Scale
    1. --c-primary-c-scale(Property + Value)
    2. --primary-c-scale(Value Specific)
    3. --c-c-scale(Property Specific)
    4. --c-scale(Global)
  5. Hue Rotate
    1. --c-primary-h-rotate(Property + Value)
    2. --primary-h-rotate(Value Specific)
    3. --c-h-rotate(Property Specific)
    4. --h-rotate(Global)

Refer to the underlying CSS properties for granular color control.

ESC

Start typing to search across the documentation.