A token can hold a value. This catalog types it
A CSS Variables entry can set --angle: 0deg. It cannot say “this is an <angle>, interpolable, initial 0deg.” Without @property, a gradient-border spin or a token color fade stays discrete or no-ops. The name is defined. The type is not.
A class cannot hold the at-rule. Class bodies wrap as [published-key] .name { … }. @property inside that rule is ignored. A token cannot hold it either — @ and braces are rejected. Project CSS Properties are the missing catalog: a project-wide map of name → syntax, inherits, initial value. Fill it once and composer, Preview, and — by default — published widgets emit the at-rule.
This page is typed @property, not the token catalog. The Variables page still defines the name. This catalog types that same --name.
When to use it / when not to
| You want | Without typed properties | With this catalog |
|---|---|---|
A token that interpolates under transition or @keyframes on a host that never registered @property | The value jumps, or the animation is a no-op, unless the host already typed the name. | RuleCMS ships @property --angle with the widget. The embed can blend. |
A host that already registered the same --names | Works today. Do not double-register. | Turn published inclusion off. Composer and Preview still use the catalog. |
@theme is one host that already does this — not a requirement. If your site already registers those names, leave inclusion off so RuleCMS does not emit a second @property.The project catalog
Open an environment, then CSS Properties. The page is project-scoped: Development, Staging, and Production share it.
- Preview dumps the catalog as emitted
@propertyblocks — not a:rootlisting and not the token catalog. - Edit is a row of name, syntax, inherits, and initial value. Type
--angle, pick<angle>, set initial0deg— not a pasted@property --angle { … }. Combined syntax strings such as"<color> | <image>"are not accepted; pick*if the value is untyped. Invalid rows are refused. Catalog Save is explicit.
Each entry is one typed custom property:
@property --angle {
syntax: "<angle>";
inherits: false;
initial-value: 0deg;
}Names must start with -- (same rule as CSS Variables). At most 40 properties; 200 characters per name and per initial value. Initial values reject url(, @, braces, and ;. Any syntax other than * requires a non-empty initial value. When syntax is * and the initial value is empty, initial-value is omitted on emit.
What the renderer does with the catalog
| Surface | What happens |
|---|---|
| Composer canvas and Preview | Always injects an unscoped @property stylesheet. The published-inclusion flag is ignored here so authors still see interpolation while they work. |
| Published widget (React SDK and HTML custom element) | The widget fetch includes the catalog when inclusion is on. The renderer emits one <style> of @property rules. The at-rule is document-global — it is not scoped to the published-key span, and the name is not prefixed. RuleCMS never styles :root or html. |
You do not republish a widget to retype a name. The catalog is joined when the host fetches the widget. The next uncached fetch picks up the current rules.
Published widgets
On the project's CSS Properties page, the Published widgets accordion holds two radios. Changing a radio saves immediately. Catalog Save is separate.
- Include these typed CSS properties when published widgets are rendered. A non-empty catalog is sent with the widget and the renderer registers the types. This is the default.
- My apps already register these @property rules. Do not include them again when the widget is being rendered. Published widgets still carry token names that need those types, but RuleCMS does not ship the
@propertyblocks. Your host stylesheet must register them.
--name the widgets animate. A missing @property on the live page leaves the token discrete.How a published widget receives the catalog
Hosts already fetch the widget once. RuleCMS hangs the catalog on that same response as a sibling of the widget, its collections, CSS variables, class definitions, fonts, keyframes, and themes — not folded into itemList. The field is cssProperties (not a vague properties).
{
"success": true,
"data": {
"widget": { "publishedKey": "…", "itemList": "…", "…": "…" },
"childCollections": { },
"cssProperties": [
{
"name": "--angle",
"syntax": "<angle>",
"inherits": false,
"initialValue": "0deg"
}
]
}
}cssProperties is omitted when the catalog is empty, when inclusion is off, or if the catalog cannot be read. When inclusion is off, the same response also sends includeCssProperties: false so renderers that still receive a list must not emit it. Missing on the payload means include (legacy clients). The widget still loads.
The React renderer (@rulecms/widget-react) and the HTML custom element turn a non-empty catalog into one <style>, for example:
@property --angle {
syntax: "<angle>";
inherits: false;
initial-value: 0deg;
}Good to know
- One catalog per project. Not per environment, not per widget.
- Same name, last widget wins.
@propertyis document-global. Two embeds that type--angledifferently will race. Use the same registration, or turn inclusion off on the host that already owns the name. RuleCMS does not rename properties per published key. - React and the HTML embed this pass. Other framework SDKs do not emit this catalog yet.
- Leave the catalog empty if the host already registered the same names. Token names on elements still work. Nothing extra is sent to the published page.
Related docs
- CSS Variables — this catalog types a name the Variables page defines
- Class Definitions — the utility bodies that often
transitionoranimatethose names - Fonts — the typeface catalog; another unscoped at-rule
- Keyframes — named
@keyframes; typed properties are what those frames can interpolate - Position try — named
@position-tryfallbacks for overlay classes - Themes — host-dark / color-scheme token overrides
- Cascade layers — wrap class definitions in
@layerso they compete with host Tailwind - Widget chrome — color-scheme and selection on the widget root
- HTML Custom Element Embed
- Development Integration
- API Reference — the public widget GET, including
cssProperties - Projects, Environments & Tokens
- The Composer