# JQHTML v2 Complete Syntax & Instruction Format Specification
## Overview
JQHTML v2 is a composable component templating language for jQuery that compiles to efficient JavaScript instruction arrays. This document defines the complete syntax specification and the instruction format that templates compile to.
## Critical Concepts
### The Instruction Array Pattern
Templates compile to functions that return arrays of rendering instructions:
```javascript
// Every template function returns this structure:
function render(Component, data, args, content) {
const _output = []; // Instruction array
// ... push instructions ...
return [_output, this]; // CRITICAL: Returns tuple [instructions, context]
}
```
### Why This Pattern Exists
1. **Deferred Execution**: Instructions can be processed when optimal
2. **Single DOM Write**: All HTML built as string, then one `$.html()` call
3. **Complex Attribute Handling**: Functions and objects can't go in HTML strings
4. **Component Coordination**: Parent/child relationships preserved through execution
## Template Syntax
### 1. Component Definition
Components are defined using the `` tag:
```jqhtml
```
### 2. $ Attribute System
JQHTML uses the `$` prefix for passing data to components as `this.args`:
#### Syntax Rules
1. **Quoted = Literal String**
```jqhtml
$title="User Profile" → args.title = "User Profile"
$expr="this.user" → args.expr = "this.user" (the string, not evaluated!)
```
2. **Unquoted = JavaScript Expression**
```jqhtml
$user=this.user → args.user = {actual user object}
$count=42 → args.count = 42
$enabled=true → args.enabled = true
$handler=this.onClick → args.handler = function reference
```
3. **Parentheses for Complex Expressions**
```jqhtml
$status=(active ? 'online' : 'offline')
$data=({...this.user, modified: true})
$items=(this.data.items || [])
```
#### Runtime Behavior
- All $ attributes become properties in `this.args` (NOT `this.data`)
- Stringable values (strings/numbers) appear as `data-*` DOM attributes
- Complex values (objects/arrays/functions) accessible only via `this.args`
- Component constructor syncs stringable args to DOM
#### Example
```jqhtml
$title="User Profile"
$count=42
data-role="admin"
/>
```
Result in UserCard component:
- `this.args.user` = {name: "Alice", id: 123} (object)
- `this.args.title` = "User Profile" (string)
- `this.args.count` = 42 (number)
- `this.args.role` = "admin" (from data- attribute)
DOM shows: `
` (no data-user since it's an object)
### 3. Expressions
Output JavaScript expressions using `<%= %>` (escaped) or `<%!= %>` (unescaped):
```jqhtml
<%= this.data.title %>
<%!= this.data.rawHtml %>
<%@= this.data.maybeUndefined %>
<%!@= this.data.maybeUndefinedHtml %>
```
### 3. Code Blocks
Execute JavaScript code using `<% %>`. Regular JavaScript passes through unchanged:
```jqhtml
<% const items = this.data.items || []; %>
<% console.log('Rendering:', items.length); %>
<% if (condition) { %>
True branch
<% } else { %>
False branch
<% } %>
<% for (const item of items) { %>
<%= item.name %>
<% } %>
```
**Design Rationale**: JavaScript code blocks pass through directly into the generated function. This allows developers to use any JavaScript construct without parser limitations. The parser only intervenes for template-specific syntax that isn't valid JavaScript (like the colon-style below).
### 4. Template Control Flow
For template-specific control flow, colon style provides PHP-like syntax:
```jqhtml
<% if (condition): %>
True branch
<% else: %>
False branch
<% endif; %>
<% for (const item of items): %>
<%= item.name %>
<% endfor; %>
```
Note: The brace style shown in Code Blocks above is regular JavaScript, not special template syntax.
## Component Invocation
### Basic Component Usage
Components are invoked using capital-letter tags:
```jqhtml
Default content
```
### Property Passing
```jqhtml
closeModal()" />
```
### $ Attribute System
JQHTML uses the `$` prefix as a shorthand for data attributes with special handling:
#### General Case: `$foo="bar"` → `data-foo`
```jqhtml
{tag: ["div", {"data-user": currentUser, "data-theme": "dark", "data-count": 42}, false]}
```
**Runtime Behavior**:
1. The attribute is set via jQuery's `.data()` method: `$element.data('user', currentUser)`
2. For debugging visibility, if the value is a string or number, it's also set as a DOM attribute
3. Objects and arrays are stored in `.data()` but not visible in DOM
#### Special Case: `$id="name"` → Scoped IDs
The `$id` attribute has special handling for component-scoped element selection:
```jqhtml
```
This happens because content functions capture their defining scope:
```javascript
// ParentComponent render
function render(_cid) { // Parent's _cid = 123
_output.push({comp: ["ChildComponent", {}, () => {
// This arrow function captures Parent's _cid
const _output = [];
_output.push({tag: ["div", {"id": "slot-element:" + _cid}, false]}); // slot-element:123
return [_output, this];
}]});
}
// ChildComponent render
function render(_cid) { // Child's _cid = 456
_output.push({tag: ["div", {"id": "child-element:" + _cid}, false]}); // child-element:456
}
```
#### Attribute Value Interpolation
Within quoted attribute values, `<%= %>` and `<%!= %>` perform string interpolation:
```jqhtml
{tag: ["div", {"title": "User: " + user.name}, false]}
```
**Design Rationale**: Inside attribute values, HTML escaping is inappropriate because we're building a JavaScript string, not HTML content. The JavaScript string serialization handles all necessary escaping (quotes, backslashes, etc.). This is semantically different from top-level `<%= %>` which outputs to HTML and requires escaping.
## Binding Syntax (v2)
### Property Binding with `:`
The `:` prefix creates dynamic property bindings that are always evaluated as JavaScript expressions:
```jqhtml
```
**Compilation**:
- `:prop="expr"` → `{"data-bind-prop": expr}` (no quotes around expr)
- Values are ALWAYS treated as JavaScript expressions
- Even quoted strings like `:prop="value"` become expressions
### Event Binding with `@`
The `@` prefix binds event handlers:
```jqhtml
updateValue(e.target.value)" />
"); // Closing tag (raw string!)
```
**CRITICAL**: Closing tags are ALWAYS raw strings, not instructions.
## Context Preservation
### v1 Pattern: `_that = this`
The v1 pattern preserves component context through nested functions:
```javascript
function render(Component, data, args, content) {
let _that = this; // Preserve component instance
let _output = [];
_output.push({comp: ["Child", {}, function(Child) {
let _output = [];
// _that still refers to parent component
_output.push(html(_that.data.value));
return [_output, _that];
}.bind(_that)]});
return [_output, _that];
}
```
### v2 Pattern: Arrow Functions
v2 uses arrow functions for natural context preservation:
```javascript
function render(Component, data, args, content) {
const _output = [];
_output.push({comp: ["Child", {}, (Child) => {
const _output = [];
// 'this' refers to parent component naturally
_output.push(html(this.data.value));
return [_output, this];
}]});
return [_output, this];
}
```
## Runtime Processing
### Phase 1: Instruction Execution
```javascript
let [instructions, context] = template.render.bind(component)(
component,
component.data,
args,
content_fn
);
```
### Phase 2: Instruction Processing
1. **Build HTML**: Process all string and simple tag instructions
2. **Track Complex Elements**: Store elements with function attributes
3. **Single DOM Write**: `component.$.html(html.join(''))`
4. **Apply Attributes**: Attach event handlers and complex attributes
5. **Initialize Components**: Create child component instances
## Self-Closing HTML Tags
The following HTML tags are automatically treated as self-closing:
- `area`, `base`, `br`, `col`, `embed`, `hr`, `img`, `input`
- `link`, `meta`, `param`, `source`, `track`, `wbr`
## Complete Example
### Template
```jqhtml
<#actions>
#actions>
<% if (this.data.loading): %>
<% else: %>
<#header>
");
return [_output, this];
}
```
## Component CSS Classes
When components are rendered, the runtime automatically applies CSS classes based on the component's inheritance hierarchy:
```html
```
This enables CSS targeting at any level of the hierarchy:
```css
.Component { /* all components */ }
.UserCard { /* specific component type */ }
.BaseCard { /* all cards */ }
```
**Implementation Note**: The Component base class automatically applies these classes during initialization. This feature works regardless of minification since class names are preserved through the component's constructor name.
## Critical Implementation Rules
### What MUST Be Preserved
1. **Instruction Array Structure**: The `{tag:...}`, `{comp:...}`, `{slot:...}` format
2. **Return Tuple**: Functions MUST return `[instructions, context]`
3. **Deferred Component Init**: Components render as placeholders first
4. **Single DOM Write**: Build all HTML, write once
5. **Content Function**: Parent components receive content function to access slots
### Common Pitfalls
1. **Forgetting Return Format**: Must return `[array, context]`, not just array
2. **String vs Instruction**: Closing tags are strings, opening tags are instructions
3. **Context Loss**: Without proper binding, nested functions lose component reference
4. **Direct DOM Manipulation**: Never manipulate DOM during instruction building
5. **Missing html() Escaping**: User content must be escaped
6. **Slots Outside Components**: Slots must be inside component content functions