Skip to content

Introduction

Core concepts

The whole model of CROFF, in five minutes.

Expressions

An expression is one token in a class attribute. It's a utility name followed by a value, optionally preceded by variants.

text
md:hover:bg(brand-dark)

Here md and hover are variants, bg is the utility and brand-dark is the argument.

Two value forms

html
<div class="gap(4) margin[0_auto]"></div>
Generated CSS
:root {
  --croff-spacing-4: 1rem;
}

.gap\(4\) {
  gap: var(--croff-spacing-4);
}

.margin\[0_auto\] {
  margin: 0 auto;
}

Parentheses take validated values: theme tokens, keywords, bounded numbers and registered functions. Brackets take raw CSS, with underscores standing in for spaces.

Tokens

Your design decisions live in a theme. A token compiles to a custom property, and only the tokens you use reach the output.

ts
import { defineConfig } from "@croff/core";

export default defineConfig({
  theme: {
    colors: { accent: "#ff5c00" },
  },
});

Now bg(accent) works, and bg(acent) is an error that suggests the fix.

Variants

Variants apply a utility conditionally. Stack as many as you need.

html
<a class="hover:color(brand) md:text-size(lg) md:hover:color(light)">Link</a>
Generated CSS
:root {
  --croff-color-brand: #c8fd12;
  --croff-color-light: #f5f2f1;
  --croff-text-size-lg: 1.125rem;
}

.hover\:color\(brand\):hover {
  color: var(--croff-color-brand);
}

@media (min-width: 768px) {
  .md\:text-size\(lg\) {
    font-size: var(--croff-text-size-lg);
  }

  .md\:hover\:color\(light\):hover {
    color: var(--croff-color-light);
  }
}

Scanning

CROFF reads your source files as text and finds what looks like an expression. It never runs your code, so class names must appear complete in the source. See Dynamic utility limitations.

The directive

Generated CSS goes wherever your stylesheet says @croff;.

css
@croff reset;
@croff;

.my-own-class {
  color: red;
}

That's the whole model. The rest of the documentation is detail.