Template Syntax

Caspian's authored syntax is split across two runtimes: Jinja renders on the server, and PulsePoint enhances the final HTML in the browser. Caspian's current syntax contract is HTML-first.

Server-Side Jinja

Use native Jinja in authored route, layout, and component HTML whenever the value is known on the server. That includes text interpolation, attribute values, and normal control flow.

index.html
<h1>Welcome, {{ user.name }}</h1>

<div class="{{ 'hidden' if not is_visible else 'block' }}">
  Server-visible content
</div>

{% if user.is_admin %}
  <p>Admin tools</p>
{% else %}
  <p>Standard dashboard</p>
{% endif %}

{% for post in posts %}
  <article>{{ post.title }}</article>
{% endfor %}
Use Jinja for values coming from page(), layout(), metadata, auth state, or other server-prepared context. In current authored templates, Jinja blocks are the default control-flow syntax.

Browser-Side PulsePoint

Use PulsePoint when the browser owns the value after first render. That means interactive text, event handlers, list updates, refs, effects, and RPC-driven UI state.

Authored PulsePoint template
<section>
  <h2>title</h2>
  <p>Count: count</p>

  <button onclick="setCount(count + 1)">
    Increment
  </button>

  <template pp-for="item in items">
    <div key="{item.id}">item.label</div>
  </template>

  <script>
    const  title, items = []  = pp.props;
    const [count, setCount] = pp.state(0);
  </script>
</section>

Use PulsePoint for

  • Inline events such as onclick, oninput, and onsubmit.
  • pp.state(...), pp.effect(...), pp.ref(...), and pp.rpc(...).
  • Client-owned template expressions like {count} and list rendering with pp-for.

Hard invariant

Author a plain <script> inside the single root. Do not handwrite pp-component or type="text/pp". Caspian injects those at render time.

Choose The Right Syntax

Server
{{ user.name }}
{% if user.is_admin %}
{% for item in items %}
Browser
count
onclick="save()"
pp-for="item in items"
A simple rule works well: if Python knows the value before the response leaves the server, use Jinja. If the browser will mutate or react to it after mount, use PulsePoint.

Native HTML Attributes

In authored route and layout HTML, prefer normal HTML attribute names: class, for, data-*, aria-*, and lowercase event attributes like onclick.

Preferred in authored HTML Avoid teaching as the default
class="card" className="card"
for="email" htmlFor="email"
data-test-id="save-button" dataTestId="save-button"
onclick="save()" onClick="save()"
Python component helpers may normalize some prop aliases before the component function runs, but the docs site's authored HTML should teach the native HTML and PulsePoint spellings the runtime expects.