if, for, or switch on a regular element like <div>, the element itself appears in the output. Sometimes you need the directive logic without an extra wrapper in the DOM — for example, inside a <table> where only <tr> elements are valid children.
Aero treats <template> in two different ways, depending on whether you use structural directives on the tag (if, else-if, else, for, data-for, switch):
| Usage | What appears in the generated HTML |
|---|---|
Structural directive on <template> | Only the inner markup — the <template> wrapper is not emitted. Wrapperless pattern: same logic as <div if> / <li data-for>, without an extra element in the tree. |
Plain <template> (no those directives) | A real <template>...</template> in the output. In the browser, that node stays inert until script moves or clones it — standard HTML behavior. |
Why wrapperless <template> exists
Correctness: If Aero left a real <template> in the document for a conditional, loop, or switch, the browser would keep the inner nodes inert — they would not behave like normal rendered content. For if / for / switch on <template>, the compiler erases the wrapper and emits only the children.
Ergonomics: You get a single logical block (multiple siblings, table rows, and so on) without a non-standard tag. <template> is parser-recognized and often allowed where an extra <div> would break the content model (for example around <tr> in tables, or inside <select>).
Wrapperless conditionals (if / else-if / else)
Use the same directives as on any other element; optional data- prefixes work the same.
<template>. You can pair a wrapperless <template if> with a <section else-if> that keeps its outer tag, and so on.
Wrapperless loops (for / data-for)
Put the loop directive on <template> to repeat only the inner fragment without a wrapper element:
<ul>; no <template> node appears in the output.
Wrapperless switch / case / default
Put switch / data-switch on <template> to match a discriminant against case branches without emitting an extra wrapper. Direct children of the container must be branch elements (case or default); see Templates for expression rules.
<div switch="{ state }">); the outer tag is preserved and only one branch’s children render inside it. Grouped matches use array syntax: case="{ ['a', 'b'] }".
Plain <template> (inert markup)
If you do not put if / else-if / else / for / data-for / switch on the <template> tag, Aero compiles it like a normal element: the generated HTML includes <template>...</template>. The inner markup is still compiled (interpolation, nested components, and so on); in the live DOM that subtree remains inert until your client code clones or adopts it.
Use that when you intentionally keep markup out of the visible tree (prototypes, dialog bodies, chunks for cloneNode, and similar patterns).
When to prefer <template> over <div>
- Wrapperless structural directives — You want a group of nodes without an extra wrapper in the output; use
<template if>/<template data-for>/<template switch>as above. - Content models — HTML only allows certain children in contexts like
<table>,<tbody>,<select>, or lists.<template>is often valid where an extra<div>is not. - Inert markup for JavaScript — You keep markup in a real
<template>(no structural directive on the tag) until a script clones it. - No extra semantics — Unlike
<div>,<template>does not imply a generic block box; it is explicitly a non-rendered holder when used as a literal element.
Attributes on wrapperless <template>
Directive attributes (if, for, switch, case, default, and so on) are compile-time only. Normal attributes on a wrapperless <template> (for example class) do not appear in the final HTML — there is no element to attach them to. Put classes and ARIA on a real element inside the fragment.