CoordiationCSS
Menu
Docs/Core concepts/Custom utilities

CORE CONCEPT · COMPLETE

Custom utilities

Extend the compiler from your CSS entry with project-owned utility names that use the same scanner, variants, prefix, important syntax, and rejection contract as built-in Coordiation classes.

Definitions omit the configured class prefix. @co-utility content-auto produces co-content-auto with the default prefix, while a project using x- receives x-content-auto.

01

Register a static utility

Use a lowercase hyphenated name and ordinary CSS declarations. A project definition takes priority when it resolves the same body as a built-in utility.

src/coordiation.css
@coordiation;

@co-utility content-auto {
  content-visibility: auto;
  contain-intrinsic-size: auto 1000px;
}
Template
<section class="co-content-auto md:co-content-auto hover:!co-content-auto">
  ...
</section>
02

Add a functional wildcard

End a pattern with one -* wildcard. Resolve the captured part through co-value(); the first matching resolver wins.

src/coordiation.css
@co-theme {
  --co-tab-size-github: 8;
}

@co-utility tab-* {
  tab-size: co-value(
    --co-tab-size-*,
    integer,
    [integer],
    co-default(4)
  );
}

This definition accepts co-tab, co-tab-github, co-tab-7, and co-tab-[13].

VALUE CONTRACT

Resolve only declared value shapes

Every functional candidate must satisfy at least one resolver in a declaration.

  1. 01

    Theme: --co-color-* resolves a matching emitted theme variable.

  2. 02

    Bare: integer, number, percentage, and ratio validate unbracketed values.

  3. 03

    Arbitrary: [integer], [number], [percentage], [ratio], [length], [color], and [*] validate bracket syntax.

  4. 04

    CSS variable: parenthesized custom properties such as (--card-size) resolve through arbitrary descriptors.

  5. 05

    Default: co-default(4) enables the wildcard root without a captured value.

03

Resolve slash modifiers separately

Use co-modifier() for the portion after an unbracketed slash. A declaration with no matching modifier is omitted while other valid declarations remain.

src/coordiation.css
@co-utility type-* {
  font-size: co-value(--co-text-*, [length]);
  line-height: co-modifier(
    --co-leading-*,
    [length],
    co-default(1.2)
  );
}
Template
<h2 class="co-type-[2rem]/tight">Readable heading</h2>
04

Keep fractions as one value

The ratio resolver treats an unbracketed slash as part of the value before trying modifier resolution.

src/coordiation.css
@co-utility frame-* {
  aspect-ratio: co-value(ratio, [ratio]);
}

Both co-frame-3/4 and co-frame-[7/9] compile to validated ratios. A zero denominator is rejected.

05

Declare negative behavior explicitly

Negative values are never inferred. Register a second pattern so reviewers and agents can see exactly which family permits negation.

src/coordiation.css
@co-utility offset-* {
  inset: calc(co-value(integer) * var(--co-space-unit));
  inset: co-value([length], [percentage]);
}

@co-utility -offset-* {
  inset: calc(co-value(integer) * var(--co-space-unit) * -1);
  inset: calc(co-value([length], [percentage]) * -1);
}
Template
<div class="co-offset-4 -co-offset-[2rem]"></div>
06

Fail before invalid CSS ships

The compiler rejects malformed names, duplicate patterns, empty or malformed declarations, unsafe candidate values, nested rules, and authored !important. Use the class important modifier so variants and output remain canonical.

Declarations only

Nested selector and at-rule contexts belong in custom variants. An @co-utility block is intentionally a flat declaration contract.

07

Inspect the project manifest

Each compile result reports project-local patterns without mixing them into the framework's global registry.

JavaScript
const result = compile(inputCss, candidates);

console.log(result.customUtilities);
// [{
//   pattern: "tab-*",
//   functional: true,
//   properties: ["tab-size"]
// }]

AI GENERATION CONTRACT

Discover before generating

Agents should treat the compile manifest and authored directives as the exact project-local API.

  • Never infer a custom utility from visual intent or a similarly named framework class.
  • Keep the full custom candidate literal so the scanner can discover it.
  • Match theme, bare, arbitrary, modifier, and default values only when their resolver declares support.
  • Generate a negative candidate only when a separate negative pattern exists.
  • Report rejected custom candidates instead of silently substituting another value.