π€ Rules for AIΒΆ
A condensed ruleset for AI tools generating Clera code. These rules prevent the most common mistakes.
π Structure rulesΒΆ
β
Always wrap everything in <app>
β
Every screen is a <page name="..."> inside <app>
β
Set id and class on <page> elements for CSS targeting
β
Include <script src="clera.js"></script> before your own scripts
β
One <app> per file. Never two.
β Never put content outside <app> except <script> and <link> tags
β Never nest <app> inside another element
β Never create multiple <app> elements
π JavaScript rulesΒΆ
β
Write plain global functions: function myAction() {}
β
Use context as the first parameter when you need it
β
Use async function for async work
β
Keep functions focused. One action, one job.
β Never use import or export
β Never use React, Vue, Svelte, or any framework
β Never write classes for actions or page logic
β Never use arrow functions as top-level action declarations. They do not get hoisted and may not be available at action resolution time.
β Never register actions before using them. Just write the function.
π Action rulesΒΆ
β
HTML action attribute value must exactly match the JS function name
β
Functions can ignore context if not needed
β
Async actions are fine. Clera handles the returned Promise.
β Never use app.actions = { ... } unless you need page-local scoping
β Never use onclick="..." for actions. Use action="..." instead.
β Never assume context is available outside an action function
π Form rulesΒΆ
β
Use <form action="functionName"> for form submissions
β
Read values with context.values.fieldName
β
Reset with context.form.reset()
β
Multiple fields with the same name become arrays automatically
β Never use document.querySelector to read form values
β Never construct FormData manually for normal form fields
β Never add onsubmit="...". The action attribute handles submission.
π DOM rulesΒΆ
β
Use context.render("#selector", html) to replace content
β
Use context.append("#selector", html) to add content
β
Use context.clear("#selector") to empty an element
β
Use context.query("#selector").text(value) for text updates
β
Use { reserveHeight: true } on render() for content-heavy containers
β Never use document.querySelector for DOM updates. Use context helpers instead.
β Never set innerHTML directly. Use context.render().
β Never reach outside the current pageβs DOM in action functions
π¨ Styling rulesΒΆ
β
Target pages with page { }, #home { }, .myClass { }
β
Set id and class on <page> in HTML to enable these selectors
β
Use app[data-layout="mobile"] for responsive breakpoints
β
Use standard CSS with no preprocessors required
β Never target div[data-pwa-page] directly. Use page selectors.
β Never target the original <page> element expecting it to be in the DOM. It is extracted at boot.
ποΈ Memory rulesΒΆ
β
Use app.memory for large datasets, cached API results, session state
β
Use standard JS to read, mutate, and delete: app.memory.x = y, delete app.memory.x
β
Move data into context.data() or app.data() when the UI needs it
β
Use memory for data that should survive page navigation without re-fetching
β Never use {memory.x} in HTML. It is not supported and resolves to "".
β Never put large datasets directly into context.data(). Use memory and slice instead.
β Never expect memory mutations to update the DOM automatically
Mistake |
Correct pattern |
|---|---|
|
|
|
|
π§© Reusable block rulesΒΆ
β
Use <template id="..."> for definition-only reusable sources
β
Use <div template id="..."> when the source should also render in place
β
Every template source must have an id attribute
β
Use <use template="id" /> to instantiate a template
β
Use name="..." on <use> when each instance needs independent data
β
Use app.map(obj, string) to build <use> strings in loops
β
Set instance data via context.instanceName.key = value
β Never put id attributes on elements inside templates. They duplicate across clones.
β Never use querySelectorAll("use"). It hits SVG. Clera uses use[template] internally.
β Never try to use app.map() as a loop. It maps one object to one string only.
β Never use a reserved context name as an instance name (navigate, render, data, etc.)
β Never share the same name across two <use> elements on the same page
Mistake |
Correct pattern |
|---|---|
|
|
|
|
Loop with |
|
|
|
π Page listener rulesΒΆ
β
Use context.listen(selector, event, callback) for page-scoped event listeners
β
Register listeners in onCreate. They persist across renders automatically.
β
Use off() to remove a listener rule when no longer needed
β
Listeners rebind automatically after context.render(), context.append(), and context.clear()
β Never re-call context.listen() with the same callback after a render. It is idempotent.
β Never use raw element.addEventListener() expecting Clera to auto-sync. Use context.listen() instead.
β Never assume context.listen() works outside a mounted page. It requires pageRecord.rootElement.
Mistake |
Correct pattern |
|---|---|
|
|
Re-calling |
Register once in |
ποΈ Data system rulesΒΆ
β
Use app.data({ key }) for global data shared across all pages
β
Use context.data({ key }) for page-local data
β
Access bound data directly: context.stats.count, app.user.name
β
Use {path} dot-notation bindings in HTML: {user.name}, {stats.count}
β
Use context.fetch() for network requests. It auto-updates the DOM.
β
Use context.timeout() for delayed mutations. It auto-updates the DOM.
β
Call context.update() or app.update() after mutations outside Clera handlers
β Never use a reserved key name as a data key (navigate, render, pageName, etc.)
β Never call context.update() inside a Clera handler. It is automatic there.
β Never deep-clone data before passing to context.data(). References are the point.
β Never use {user.getName()}. Binding syntax accepts data paths only, not expressions.
Mistake |
Correct pattern |
|---|---|
|
|
|
|
|
Choose a non-reserved key name |
|
|
β οΈ Common mistakes to avoidΒΆ
Mistake |
Correct pattern |
|---|---|
|
|
|
|
|
|
|
|
|
Just write the function globally |
Styling |
|