Skip to main content
Every .html file in Aero is a template. The same syntax — { } expressions, directives, <script is:build> — works in all of them. The difference is where the file lives and what role it plays:

Template auto-import

By default (templateAutoImport: true), Aero resolves -layout and -component tags from your project tree. You do not need a matching import in <script is:build> for each tag. The build, aero check, and the VS Code extension use the same rules: tag base name → client/layouts/*.html or client/components/**/*.html. Still import explicitly: @content/*, npm packages, .ts / .js modules, and assets (@images/*, etc.). When to add an explicit template import:
  • Override — pin a non-default file for the same binding (e.g. import footer from '@components/theme/footer.html' for <footer-component />).
  • Disambiguation — two files share a basename (e.g. components/toggle.html and components/theme/toggle.html); Aero errors until you import one path explicitly.
  • Opt-out — set templateAutoImport: false in aero.config.ts to require imports for every layout/component (legacy behaviour).
Tag demo-list-component maps to binding demoList and file **/demo-list.html under components. Layout tags only search client/layouts/ (non-recursive); component tags search client/components/ recursively.

Pages

Every .html file in client/pages/ becomes a route. index.html maps to /, about.html maps to /about. See Routing for dynamic routes and getStaticPaths.
client/pages/about.html

Components

Components are .html files in client/components/. Use them as custom elements with the -component suffix; no import is required unless you are overriding or disambiguating (see Template auto-import):
client/components/greeting.html
client/pages/index.html
Explicit imports use the .html extension: import greeting from '@components/greeting.html'. When you add one, it overrides auto-import for that binding.

Props

Pass data to a component via attributes. Use { } for dynamic values:
Inside the component, destructure from Aero.props:
Spread an object with props="{ ...obj }" to pass every key as a separate prop:
Use self-closing syntax (/>) when a component has no slot content. Use opening and closing tags to pass children into its <slot>:

Layouts

Layouts are .html files in client/layouts/ that wrap page content. Use <slot /> to mark where the content goes:
client/layouts/base.html
client/pages/about.html

Nested layouts

A layout can use another layout. Content flows from page to inner layout to outer layout:
client/layouts/docs.html

Named slots

Define named slots with the name attribute. Pages target them with slot:
client/layouts/base.html
client/pages/home.html

Expressions

Wrap any JavaScript expression in single braces to interpolate it into text or attributes:
Text interpolations are HTML-escaped by default. Use raw() for intentional unescaped HTML:

Loops

Use for (or for) with a for…of expression to repeat an element:
Inside the loop body, Aero provides index, first, last, and length as automatic variables.

Conditionals

Use if, else-if, and else as attributes:

Switch / case

Match a value against multiple alternatives:

Wrapperless output with <template>

Put a directive on <template> to emit only the children without a wrapper element:
This works with if, for, and switch. It is especially useful inside <table> or <select> where an extra <div> would be invalid.
All directive attributes also accept a data- prefix for strict HTML spec compliance: for, if, else, etc.