Use built-ins in a class body. Catalog only custom names
Anchor positioning already ships fallback names such as flip-block and flip-inline. Those belong in a Class Definitions body:
position: absolute; position-try-fallbacks: flip-block;
Do not add flip-block to this catalog. It is a built-in. A class cannot hold a custom try set either: @position-try inside [published-key] .name { … } does not register, and a token cannot hold the block (@ is rejected). This catalog is only for your dashed idents — names like --flip that a class then points at with position-try-fallbacks: --flip.
Authors type --flip and the declarations. RuleCMS emits the unscoped at-rule. You never paste @position-try --flip { … }.
When to use it / when not to
| You want | Without this catalog | With this catalog |
|---|---|---|
A copied overlay class that says position-try-fallbacks: flip-block | Works today. The UA already knows flip-block. Leave this page empty. | Do not catalog the built-in. Keep it on the class. |
A host design system that defines --flip as a custom try set | The class is present. The popover does not flip unless the host already registered @position-try --flip. | RuleCMS ships the at-rule with the widget. Preview matches the embed. |
| A host that already registers the same try sets | Works today. Do not double-define. | Turn published inclusion off. Composer and Preview still use the catalog. |
The project catalog
Open an environment, then Position try. The page is project-scoped: Development, Staging, and Production share it.
- Preview dumps the catalog as emitted
@position-tryblocks — not a:rootlisting. - Edit is a dashed ident plus a textarea for the declaration list. Type
--flipandposition-area: top;, not@position-try --flip { … }. Invalid names and bodies are refused per row. Catalog Save is explicit.
Each entry is one custom try set:
@position-try --flip {
position-area: top;
inset: auto;
}Names must start with --, then a letter or underscore. At most 16 fallbacks; 2000 characters per body. Nested rules, url(, @, and a pasted @position-try wrapper are rejected. Built-in names without -- — flip-block, flip-inline — are refused as catalog names.
What the renderer does with the catalog
| Surface | What happens |
|---|---|
| Composer canvas and Preview | Always injects an unscoped @position-try stylesheet. The published-inclusion flag is ignored here so authors still see the fallback 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 @position-try rules. The at-rule is document-global — it is not scoped to the published-key span, and the name is not prefixed. |
You do not republish a widget to restyle a try set. The catalog is joined when the host fetches the widget. The next uncached fetch picks up the current declarations.
Published widgets
On the project's Position try page, the Published widgets accordion holds two radios. Changing a radio saves immediately. Catalog Save is separate.
- Include these position-try fallbacks when published widgets are rendered. A non-empty catalog is sent with the widget and the renderer defines the try sets. This is the default.
- My apps already register these @position-try rules. Do not include them again when the widget is being rendered. Published widgets still carry class names that point at those fallbacks, but RuleCMS does not ship the
@position-tryblocks. Your host stylesheet must define them.
@position-try --flip on the live page leaves the overlay where it first landed.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, and fonts — not folded into itemList.
{
"success": true,
"data": {
"widget": { "publishedKey": "…", "itemList": "…", "…": "…" },
"childCollections": { },
"positionTry": {
"--flip": "position-area: top;\ninset: auto;"
}
}
}positionTry 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 includePositionTry: false so renderers that still receive a map 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:
@position-try --flip {
position-area: top;
inset: auto;
}Good to know
- One catalog per project. Not per environment, not per widget.
- Same name, last widget wins.
@position-tryis document-global. Two embeds that define different declarations for--flipwill race. Use the same try set, or turn inclusion off on the host that already owns the name. - Browser support is CSS anchor positioning. Older browsers ignore the at-rule and keep the first position.
- React and the HTML embed this pass. Other framework SDKs do not emit this catalog yet.
- Leave the catalog empty if the host owns every custom try set, or if you only use built-ins. Class names on elements still work. Nothing extra is sent to the published page.
Related docs
- Class Definitions — put
position-try-fallbacks: flip-blockor--flipon a class body - CSS Variables — the token catalog
- Fonts — the typeface catalog; another unscoped at-rule
- Keyframes — named
@keyframes; the same name-plus-body pattern - Themes — host-dark / color-scheme token overrides
- CSS Properties — typed
@property - 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
positionTry - Projects, Environments & Tokens
- The Composer