Template Syntax
Caspian uses a Stack-Based Parser (Lexer) to render HTML. This ensures robust handling of deeply nested components, complex attribute logic, and dynamic expressions without the fragility of Regex.
Dynamic Expressions
Inject Python variables directly into your HTML using double square
brackets [[ ]]. The parser strictly respects boundaries, allowing for complex
logic and Python-style negation inside attributes.
<span> [[ user.name ]] </span> <!-- Python Negation & Expressions --> <div class="[[ 'hidden' if not is_visible else 'block' ]]"> Conditional Visibility </div>
Control Flow
Use the <template> tag with casp-* directives. Unlike regex-based engines, Caspian's
stack parser handles infinite nesting of loops and conditionals correctly by tracking the opening and closing of tags in a stack.
Supported Directives
casp-for
Iterate over lists or dicts.
casp-if
Conditional rendering (fully supports not negation).
casp-elif
Else-If logic for complex branching.
casp-else
Fallback rendering when conditions aren't met.
<template casp-if="not user.is_authenticated"> <button>Login</button> </template> <template casp-for="category in categories"> <h3>[[ category.name ]]</h3> <template casp-for="item in category.items"> <template casp-if="item.is_active"> <span>[[ item.name ]]</span> </template> </template> </template>
Under the Hood
Caspian transpiles semantic HTML tags into high-performance Jinja2 blocks. This allows you to maintain clean HTML while leveraging Python's full power. The CaspianParser converts [[ ]] to variable placeholders and <template> directives to block delimiters.
<template casp-if="user.admin">
<p>Access Denied</p>
</template>
[% if user.admin %] <p>Access Denied</p> [% endif %]
<template casp-if="not user.admin">
<p>Access Denied</p>
</template>
[% if not user.admin %] <p>Access Denied</p> [% endif %]
<template casp-for="post in posts">
<h1>[[ post.title ]]</h1>
</template>
[% for post in posts %] <h1>[[ post.title ]]</h1> [% endfor %]
Smart Attributes
Caspian automatically normalizes attributes through html_attrs.py. You can use React-style
camelCase props, and they will be converted to valid HTML kebab-case
automatically.
| Input (Python/JSX) | Output (HTML) |
|---|---|
| className="foo" | class="foo" |
| htmlFor="id" | for="id" |
| dataTestId="123" | data-test-id="123" |
| isDisabled={True} | disabled="true" |