Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions guides/release/components/template-tag-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,54 @@ export default CustomSelect;

This can be a powerful refactoring technique to break up large components into smaller ones. (where it makes sense!)

## Low-level format

All of template-tag format can be represented in it's pure javascript form using `template` from either `@ember/template-compiler` or `@ember/template-compiler/runtime`.

Creating a template-only component via the runtime compiler:

```gjs
import { template } from '@ember/template-compiler/runtime';

const hello = 'Greetings';

export default template(`{{hello}}`, {
scope: () => ({ hello }),
});
```

And a class-component:

```gjs
import { template } from "@ember/template-compiler";

const message = "Hello there";

class Example extends Component {
static {
template(
"Hello {{message}}",
{
component: this,
scope: () => ({ message }),
},
);
}

}
```

If in an environment with compilation, omitting the `/runtime` at the end of the import allows ahead-of-time compilation to occur on components created with `template()` for better runtime performance.

Without specifying `/runtime`, there are additional restrictions required for the argument passed to `template()`:
- it must be a string literal

With the `/runtime`, the argument passed to `template()` can be an expression, for example:
Copy link
Contributor

@sukima sukima Oct 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you say expression does that also include support for interpolation?

export default template`<div>${someValue}</div>`;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nay -- interpolation is a hazard because it can't be reactive as far as I know -- ideally we'd even add a lint that prevents that.

if reactivity is not needed, then I don't see a reason why this wouldn't work (I expect it to work -- just not be reactive on changes to someValue)

export default template(`<div>${someValue}</div>`);

```js
/* someValue could be from anywhere */
export default default template(someValue);
```

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would help (me) to see example use cases for the different possibilities. Maybe when to precompile during a <script> tag in the HTML <head> versus dynamically from a <textarea>. The difference between scope: and ${stringInterpolation}. Use of this in a build tool versus use of this in an HTML file. And how this might look used in a QUnit test or Vitest.

## Testing

Historically, Ember's integration tests have been written using the `hbs` tagged template literal. This is no longer necessary with the template tag format. Instead, use the `<template>` tag to define a template to render.
Expand Down
Loading