Maple
⌘K
DOCUMENTATIONv2.0.17

Utilities

Maple utility classes are the building blocks of your UI. They follow a flexible property-value pair syntax that resolves through a variable-first architecture.

Utility Format

Utilities are composed of a property and a value, separated by either a hyphen or an equal sign:

property-value
or
property=value
Semantic Fallback (-)
The value is resolved through the CSS variable fallback chain (e.g., bgc-primary).
Literal String (=)
The value is treated as a literal string, bypassing variable resolution (e.g., bgc=#010101).

Property and Value

  • property: The CSS property to apply. All CSS properties are supported in camelCase format. Some properties have shorthand versions. See the Abbreviations reference for the full list.
  • value: The value to apply to the property. With equal sign, the value is treated as a literal string. With hyphen, the value is resolved to semantic fallback chain of CSS variables. The type of the property determines how the value is resolved. There are four types of properties: variable, color, number, and custom.

CSS Variables

Maple allows you to define CSS variables directly in class names. This allows you to create scoped themes and dynamic styles entirely within your HTML:

<!-- Simple variable -->
<div class="--primary=blue"></div>

<!-- Complex values -->
<div class="--gradient=linear-gradient(to_right,red,blue)"></div>

<!-- Using other variables -->
<div class="--accent=var(--primary)"></div>
Deep Dive: Variable Utilities
Learn how to combine CSS variables with media queries and selectors to build fully scoped, component-level themes in the Variable Utilities guide.

Color Resolution

Colors in Maple are high-dimensional. When you use a color utility (like c-primary or bgc-accent), it resolves into a sophisticated OKLCH color space manipulation:

.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 architecture allows you to create a complete design system by defining just a few base variables. The resolution follows a strict priority:

  1. Property-Specific: --bgc-primary. Each property first looks for a CSS variable prefixed with its name (e.g., bgc-primary resolves looking for --bgc-primary).
  2. Type-Specific: --color-primary. The first fallback is the type of the property (e.g., color properties look for --color-primary).
  3. Value-Specific: --primary. The second fallback is the name of the value itself as a CSS variable.
  4. Literal: primary. The final fallback is the value itself. You can use named CSS colors that browsers support directly (e.g., c-red, bgc-blue, brc-silver). Invalid literals are silently ignored.

Tones and Transparency

You can generate an wide range of tones and alpha variations from any base color without defining them explicitly:

  • Tones: Append -{number} (e.g., c-primary-200). 500 is the mid-tone; lower numbers move toward white, higher numbers move toward black.
  • Transparency: Append /{number} (e.g., c-primary-200/68 for 68% opacity).

In the example below, we define a primary color using the --primary variable. Then, we use the bgc-primary-200/50 class to set the background color to 50% of the primary color's 200 shade, and the c-primary-700 class to set the text color to the primary color's 700 shade.

Locally Themed Component
This component mathematically generates its own shades and contrast on the fly.

<div class="--primary=oklch(0.6_0.2_90)">
  <div class="bgc-primary-200/50 c-primary-700 p-4 rad-3 fs-3.5">
    <div class="fw-600 mb-2">Locally Themed Component</div>
    This component mathematically generates its own
    shades and contrast on the fly.
  </div>
</div>
  
Color System
Maple's color system is powered by OKLCH mathematics. For a deep dive into how colors resolve, fallback, and scale, check out the Color System page.

Number Resolution

Properties that accept numeric values (spacing, time, angles, unitless) handle resolutions automatically. If a number is provided, Maple applies a default unit or calculation:

/* Spacing: Resolved via --spacer (default 0.25rem) */
.p-4 { padding: var(--p-4, var(--space-4, calc(4rem * var(--spacer, 0.25)))); }

/* Timing: Defaults to ms */
.tsdur-300 { transition-duration: var(--tsdur-300, var(--time-300, 300ms)); }

/* Angle: Defaults to deg */
.rot-15 { --tf-rot: rotate(var(--rot-15, var(--angle-15, 15deg))); }

/* Unitless: Passed as is */
.z-4 { z-index: var(--z-4, 4); }

/* Opacity: Special handling (0-100 to 0.0-1.0) */
.o-6 { opacity: 0.06; }

This architecture allows you to create a fluid design system while maintaining granular control. The resolution follows a strict priority:

  1. Property-Specific: --p-4. Each property first looks for a CSS variable prefixed with its name and value name.
  2. Type-Specific: --space-4. The first fallback is the shared type of the property (e.g., all spacing utilities look for --space-*).
  3. Literal / Calculation: The final fallback is either a calculated value for numbers (e.g., calc(4rem * var(--spacer, 0.25))) or the literal name for tokens.

Tokens and Strings

Number properties can also accept string values to be used as design tokens. When using a string, at least one fallback variable must be defined to ensure the rule is valid:


/* Spacing */
.p-md { padding: var(--p-md, var(--space-md, var(--md, md))); }

/* Time */
.tsdur-fast {
  transition-duration: var(--tsdur-fast, var(--time-fast, var(--fast, fast)));
}

/* Angle */
.rot-lg { --tf-rot: rotate(var(--rot-lg, var(--angle-lg, var(--lg, lg)))); }

/* Unitless */
.z-max { z-index: var(--z-max, var(--max, max)); }

/* Opacity */
.o-half { opacity: var(--o-half, var(--half, half)); }
  

Negative Values

Maple supports two syntaxes for negative values:

  • Prefix Syntax: -m-4. Adding - before the property negates the entire resolved value. Best for tokens.
  • Inline Negative: m--4. Uses a negative number in the value directly. This generates a negative calculation that can still be overridden via specific variables like --space--4.

/* Prefix Syntax: Negates the result */
.-m-4 {
  margin: calc(var(--m-4, var(--space-4, calc(4rem * var(--spacer, 0.25)))) * -1);
}

/* Inline Negative: Resolved as negative number */
.m--4 {
  margin: var(--m--4, var(--space--4, calc(-4rem * var(--spacer, 0.25))));
}
  

The prefix syntax is ideal for negating shared design tokens, while inline negatives are best for specific layout offsets:

<!-- Prefix syntax negating a spacer-based token -->
<div class="-m-4"></div>

<!-- Inline negative for a specific offset -->
<div class="m--4"></div>
<div class="m--4_-5"></div>
Default (0.25)
Doubled (0.5)

<div class="--spacer=0.5 bgc-body-100/50 p-4 rad-2 fs-3">
  <!-- All numeric values (p-4, rad-2, fs-3, etc.) will be doubled -->
</div>
  

1 Unit Shorthands

Absolute and relative units have shorthand syntax for "1 unit". This allows for extremely concise class names when setting base sizes or resetting dimensions:


/* Absolute Shorthand (resolves to 1 unit) */
.w-px { width: 1px; }
.m-cm { margin: 1cm; }

/* Relative Shorthand (resolves to 1 unit) */
.w-rem { width: 1rem; }
.fs-em { font-size: 1em; }
  

The following units are supported for the "1 unit" shorthand:

Type
Supported Units
Absolute

px, cm, mm, in, pt, pc, Q

Relative

rem, em, ch, ex, cap, ic, lh, rlh, fr

Cover Unit Shorthands

There are also shorthands for covering the viewport or container. These resolve to 100% or 100 units of the viewport/container:


/* Percentage (resolves to 100%, <img class="w-%">) */
.w-\% { width: 100%; }

/* Viewport (resolves to 100 viewport units, <div class="h-vh"></div>) */
.h-vh { height: 100vh; }
.w-vw { width: 100vw; }

/* Container (resolves to 100 container units, <div class="h-cqh"></div>) */
.h-cqh { height: 100cqh; }
.w-cqw { width: 100cqw; }
  

The following units are supported for the "cover" shorthand:

Type
Supported Units
Percentage

%

Viewport

vh, vw, vmin, vmax, vi, vb

Viewport (Dynamic)

dvh, dvw, dvmin, dvmax

Viewport (Small)

svh, svw, svmin, svmax

Viewport (Large)

lvh, lvw, lvmin, lvmax

Container

cqw, cqh, cqi, cqb, cqmin, cqmax

Custom Resolution

Any property that is not a color or number is considered a custom property. These follow a standard semantic fallback chain without additional transformations:


/* Font Family */
.ff-main { font-family: var(--ff-main, var(--main, main)); }

/* Opacity */
.o-half { opacity: var(--o-half, var(--half, half)); }
  

This allows you to define generic tokens that can be used across different properties. The resolution follows these steps:

  1. Property-Specific: --ff-main. Looks for a variable prefixed with the property name (or shorthand) and the value.
  2. Value-Specific: --main. Falls back to a variable named directly after the value.
  3. Literal: The final fallback is the value name itself (e.g., main).

Reserved Values

When you use standard CSS keywords in a fallback chain, Maple treats them as literal strings instead of trying to resolve them as variables. This includes values like: initial, inherit, unset, revert, none, auto, transparent, currentColor, solid, dashed, and dotted.


/* Treating keywords as literals */
.w-auto { width: auto; }
.fs-inherit { font-size: inherit; }
.bgc-transparent { background-color: transparent; }
.bgimg-none { background-image: none; }
  

Arbitrary Values

When you need to bypass Maple's variable resolution and set an arbitrary value directly, you can use the Equal Sign = or Bracket [] syntax:

  • Equal Sign: Use instead of a hyphen to pass the value directly to CSS

    
    <div class="bgc=red"><!-- background-color: red --></div>
    <div class="w=100px"><!-- width: 100px --></div>
    <div class="br=1px_solid_black"><!-- border: 1px solid black --></div>
      
  • Brackets: Use for inline custom values or when your value contains characters that Maple uses as delimiters (like colons or spaces).

    
    <div class="bgimg-url|[https://example.com/image.jpg]">
      <!-- background-image: url(https://example.com/image.jpg) -->
    </div>
    <div class="m-4_[calc(100%_-_20px)]">
      <!-- margin: 1rem calc(100% - 20px) -->
    </div>
      
Pro Tip
Use equal sign syntax for simple values. Use bracket syntax when your value contains special characters like colon. Even with equal sign, brackets may be needed: bgimg=[url(https://example.com/image.jpg)].

Special Character Handling

Maple uses reverse scanning to detect reserved delimiters (:, (), -, etc.). Single quotes, double quotes, and brackets control parsing depth—content inside them is treated as a single value. The key difference is:

  • Brackets [] are removed from the output
  • Quotes '...' or "..." are preserved in the output

<div class="bgimg=[url(https://example.com/image.jpg)]">
  <!-- background-image: url(https://example.com/image.jpg); -->
</div>

<div class="bgimg=url('https://example.com/image.jpg')">
  <!-- background-image: url('https://example.com/image.jpg'); -->
</div>

<div class="@supports=[backdrop-filter:blur(1px)]:bdblur-4">
  <!-- Brackets protect the colon in the @supports query -->
  <!-- @supports (backdrop-filter:blur(1px)) { ... } -->
</div>
  

Dynamic Values

For values that change frequently (like scroll position, mouse coordinates, or sliders), generating unique persistent classes for every value can grow the CSSOM and hurt performance. Maple provides Dynamic Classes.

Prefix any class with $$ to mark it as dynamic. Dynamic classes:

  • Are written to a special ephemeral CSS layer.
  • Do not pollute the main stylesheet.
  • Are automatically cleared and replaced on the next update cycle.

This is useful for integrating JS-driven values with Maple's utility system without adding a permanent rule for every intermediate value.


/* Example: using a slider to update CSS variables dynamically */
const slider = document.getElementById('slider');
const preview = document.getElementById('preview');

// Input event: Frequent updates use $$ (Dynamic)
slider.addEventListener('input', (e) => {
  const val = e.target.value;

  /**
   * These classes are transient and cleared automatically
   * on next frame/update
   */
  preview.classList.add(`$$--p-spacer=${val}`, `$$--g-spacer=${val}`);
});

// Change event: Final value uses standard class (Persistent)
slider.addEventListener('change', (e) => {
  const val = e.target.value;

  // These are standard static classes
  preview.classList.add(`--p-spacer=${val}`, `--g-spacer=${val}`);
});
  
Pro Tip
Always use standard classes for static design tokens and reserve $$ for high-frequency runtime updates to keep the main stylesheet lean.

Important Modifier

When you need to forcefully override a style, you can apply the native CSS !important flag directly to any utility class. Maple provides two ways to write this syntax, though the prefix approach is highly recommended for readability.

1. The Prefix Syntax (Recommended)

Place an exclamation mark ! at the very beginning of the utility string. Even if you are writing a long chain of media queries and selectors, the ! always goes at the front of the class name.


<div class="!bgc-red"></div>
<div class="!bgc=red"></div>
<div class="!@md:^:rtl:bgc=red"></div>
  

2. The Suffix Syntax

Alternatively, you can append _!important directly to the end of the value like regular CSS.


<div class="bgc-red_!important"></div>
<div class="bgc=red_!important"></div>
<div class="@md:^:rtl:bgc=red_!important"></div>
  
ESC

Start typing to search across the documentation.