Documentation menu

Template language

This page defines the Handlebars subset implemented by the current Goldar compiler. It is a reference, not a proposal: syntax absent from this page must be treated as unsupported even when another Handlebars implementation accepts it.

The compiler produces a server-renderable View program, a TypeScript typecheck probe, extracted styles, and imported-template dependency metadata from the same semantic model. Any compiler error prevents View-program emission. The recoverable source document, typecheck probe, styles, and diagnostics remain available to editor tooling.

Frontmatter and props

TypeScript frontmatter is optional. When present, it must start at byte zero, use opening and closing --- delimiters on their own lines, and declare a Props type alias:

---
type Props = {
	readonly title: string;
	readonly visible: boolean;
};
---

<h1>{{title}}</h1>

Templates without frontmatter keep the broad ambient CompiledTemplate<object> type. A template with frontmatter but no live type Props declaration is invalid. Text inside TypeScript comments, quoted strings, or template strings does not count as a declaration or a compile directive.

Goldar passes ordinary frontmatter through to the generated TypeScript declaration and typecheck probe. The only compiler-owned TypeScript statements are relative template imports and their alias calls, described below.

Expressions

Expressions are simple dot-separated paths rooted at Props or at an explicit each binding:

<p>{{account.profile.name}}</p>

Double mustaches HTML-escape the resolved value. The runtime accepts strings, numbers, booleans, null, and undefined; nullish values render as empty text. Triple mustaches require the branded TrustedHtml value created by Goldar’s runtime API:

<article>{{{trustedBody}}}</article>

Triple mustaches are an explicit trust boundary. Arbitrary strings are rejected at runtime rather than written as HTML.

Helpers, subexpressions, bracket indexing, implicit this, ../ traversal, @index, and other Handlebars metadata are not implemented.

Elements and attributes

Goldar emits ordinary HTML elements, doctypes, comments, and text. Non-void literal elements need explicit closing tags. HTML void elements may omit a closing tag and must not be closed explicitly.

Lowercase hyphenated tags are custom-element capabilities. The build integration maps each tag to one local component module unless the tag is a lexically imported template alias. Custom elements are still literal elements and therefore need explicit closing tags.

Attributes support three forms:

<input required>
<p class="summary"></p>
<user-card user={{account}}></user-card>
  • A valueless attribute is boolean presence.
  • A static value is a quoted or unquoted string and is HTML-escaped during rendering.
  • A dynamic value contains exactly one simple path and no surrounding static text.

For a bound attribute, false, null, and undefined omit the attribute; true emits presence; strings and numbers emit an escaped value. Other runtime values are rejected. Mixed values such as class="user-{{id}}" are not implemented. Property bindings, event handlers, and action syntax are also outside the current language.

Conditionals and iteration

The two implemented block forms accept only simple paths and both support {{else}}:

{{#if account.active}}
	<p>Active</p>
{{else}}
	<p>Inactive</p>
{{/if}}

{{#each accounts as account}}
	<p>{{account.name}}</p>
{{else}}
	<p>No accounts</p>
{{/each}}

if follows JavaScript truthiness. each requires an array and an explicit identifier. Its body can resolve the new lexical binding and root props. The empty branch runs in the outer scope. Nested bindings must not shadow another active binding. unless, implicit-context iteration, index metadata, and destructured bindings are not implemented.

Outlets

{{outlet}} renders the child views supplied when a compiled template is called. A template may contain at most one outlet, and the expression is valid only in content:

<main>{{outlet}}</main>

Imported templates

A template may default-import another relative .hbs file and assign it one lowercase, hyphenated local tag with .as():

---
import AccountCard from "./account-card.hbs";

AccountCard.as("account-card");

type Props = {
	readonly account: {
		readonly name: string;
	};
};
---

<account-card account={{account}} />

Imported-template calls may be self-closing or may contain outlet children. The build integration resolves their modules, checks for missing dependencies and cycles, and passes the compiled child templates into dependency slots in lexical order. Imports must be relative, must end in .hbs, and must have exactly one static alias. goldar-outlet is reserved.

Unlike a literal custom element, an imported-template tag is a server-side template call; it is not reported as a browser component capability.

Template styles

Top-level <style> elements are compile directives and do not render as markup:

<style>
	.card { color: rebeccapurple; }
</style>

<article class="card">{{title}}</article>

Goldar scopes ordinary blocks with a deterministic data-goldar-s-* attribute. A valueless is:global attribute opts out for the complete block, and :global(...) escapes an individual selector in the Node stylesheet transform. Style directives must be top-level, static, non-self-closing, and explicitly terminated. Handlebars interpolation and authored data-goldar-s-* attributes are rejected. Scoped keyframes are not implemented; global keyframes remain available.

Unsupported syntax

AreaNot implementedCurrent alternative
ExpressionsHelpers, subexpressions, bracket accessPrepare values in application code and pass props
Contextthis, ../, @index, implicit each contextUse root paths and explicit as name bindings
Blocksunless, custom blocks, destructuringUse if, each, and explicit props
AttributesMixed interpolationPass one complete value
DOM behaviorEvents, properties, actionsUse a Custom Element boundary
CompositionMultiple outlets or named slotsCompose imported templates or one layout outlet
CSSScoped keyframes and dynamic CSSUse global keyframes and CSS custom properties

Diagnostic catalog

All codes below are compiler or build errors today. An error aborts generated declaration updates and View-program emission; tools may still use recoverable editor artifacts.

CodeCondition
GOLDAR1001Unterminated opening tag
GOLDAR1002Unterminated HTML comment
GOLDAR1003Unterminated doctype
GOLDAR1004Closing tag without an element name
GOLDAR1005Unterminated closing tag
GOLDAR1006Unterminated Handlebars expression
GOLDAR1007Unexpected closing tag
GOLDAR1008Closing tag does not match the active element
GOLDAR1009Element is missing a closing tag
GOLDAR1010Void element has a closing tag
GOLDAR1011Non-void literal element is self-closing
GOLDAR1101Unsupported, unterminated, or mismatched Handlebars block
GOLDAR1102Helper, subexpression, indexed path, or other complex expression
GOLDAR1103Triple-mustache syntax used as an attribute
GOLDAR1104Event attribute or event modifier
GOLDAR1105Element property binding
GOLDAR1106Template action syntax
GOLDAR1107More than one outlet
GOLDAR1108Implicit context, traversal, metadata, or non-simple path
GOLDAR1109Mixed static and dynamic attribute value
GOLDAR1110Empty Handlebars expression
GOLDAR1111Outlet used in an attribute
GOLDAR1113Nested each binding shadows an active binding
GOLDAR1200Frontmatter opener is not followed by a newline
GOLDAR1201Unterminated frontmatter
GOLDAR1202Frontmatter does not declare a live Props type alias
GOLDAR1210Template import is not a relative .hbs specifier
GOLDAR1211Alias call has no matching default template import
GOLDAR1212Alias is not a static lowercase hyphenated string
GOLDAR1213Alias uses a reserved tag
GOLDAR1214More than one import claims the same alias
GOLDAR1215One imported binding declares more than one alias
GOLDAR1300Style directive is nested
GOLDAR1301Style directive is unterminated
GOLDAR1302Style directive has unsupported attributes
GOLDAR1303Style directive is self-closing
GOLDAR1304Style directive contains Handlebars interpolation
GOLDAR1305Template authors a compiler-reserved scope attribute
GOLDAR_TEMPLATE_DEPENDENCY_MISSINGAn imported template file does not exist
GOLDAR_TEMPLATE_DEPENDENCY_CYCLEImported templates form a cycle
GOLDAR_COMPONENT_MODULE_MISSINGNo local module implements a custom-element tag
GOLDAR_COMPONENT_MODULE_AMBIGUOUSMore than one local module could implement a tag
GOLDAR_COMPONENT_NOT_REGISTEREDA compiled module requests an unavailable component
GOLDAR_STYLE_SYNTAXThe Node CSS transform cannot parse extracted CSS
GOLDAR_STYLE_KEYFRAMESA scoped style contains unsupported keyframes

Numbers not listed in this catalog are not public aliases for another diagnostic.