1CL syntax and control flow
1CL adds bindings, conditions, loops, and components to HTML. It is not a JavaScript expression language: function calls, calculations, filters, ternaries, else, and compound and/or conditions are unsupported. Use runtime data and structure your markup around it.
Text and attribute bindings
<h2>{{ ui.title }}</h2>
<p>{{ ui.description }}</p>
<div data-framework="{{ config.framework.type }}">{{ ui.title }}</div>Bindings read dot-separated paths. Missing/null text renders no text. Strings become text nodes: bound markup displays as text, not inserted HTML. Keep ordinary content in localized settings rather than hard-coding one language.
Inside tags, bindings must be in quoted attributes. Mixed values work in ordinary HTML attributes:
<div class="category category-{{ category.id }}" aria-label="{{ category.name }}">
{{ category.name }}
</div>Bare bindings such as <div {{ attributes }}> and attribute spreading are unsupported. A whole-attribute binding removes the attribute for false, null, or undefined; true creates a boolean attribute. Empty strings remove ordinary attributes. Classes are whitespace-normalized; zero remains an attribute value.
Conditions
[[if appearance.showClose]]
<button type="button" data-1c="command:close">{{ ui.button.close }}</button>
[[/if]]
[[if not categories]]
<p>{{ ui.description }}</p>
[[/if]]False values are false, zero, empty strings, null/undefined, and empty arrays. Non-empty arrays and empty objects are true. Close both condition forms with [[/if]].
Nested conditions need an intervening HTML element; directly nested sibling markers are rejected:
[[if categories]]
<div>
[[if appearance.showCategoriesInNotice]]
<p>{{ ui.title }}</p>
[[/if]]
</div>
[[/if]]Loops
<ul>
[[each category in categories]]
<li>
<h3>{{ category.name }}</h3>
<ul>
[[each service in category.services]]
<li>{{ service.name }}</li>
[/each]
</ul>
</li>
[/each]
</ul>Loops require arrays; missing/non-array values render no items. Each item extends the caller scope, so ui remains available. Close with [/each], one bracket pair. Separate nested loops with an HTML element so markers pair correctly. There is no built-in index variable, filtering, sorting, or object enumeration.
Views
Start a view file with @view main, @view details, or @view trigger as the first non-empty line at column zero. Reusable partials must not start with @view. Canonical file names and kinds determine published views; a directive does not rename a protected file. See components.
Security boundaries
The compiler rejects script, iframe, object, and embed elements, inline on* handlers, and literal javascript: attribute values. Use commands instead of scripts. Bind trusted configuration URLs and retain the disclosures and choices required by your configured framework.