tshtml is a TypeScript-first way to author Angular templates.
In Angular projects, .tshtml files are executed at build time to produce a template string. That output is usually an Angular template (with bindings/directives), and Angular still evaluates those bindings at runtime.
- Templates are written as TypeScript modules and executed during the webpack build process
- The output becomes the template string used by your Angular components
- Ships with a webpack loader (
tshtml-loader) that turns.tshtmlfiles into HTML - Includes a small CLI (
tshtml-to-html) that can compile.tshtmlto.htmlfor debugging or non-webpack workflows - Provides a small runtime API (
tag,html,cssClass,expr, etc.) for programmatic template generation
- TypeScript interpolation (
${ ... }) runs at build time (when webpack executes the module). - Angular bindings (
{{ ... }},*ngIf,*ngFor,[(ngModel)], etc.) run at runtime (in the browser).
Most Angular usage of tshtml is: use TypeScript to emit Angular template syntax.
tshtml is most useful for:
- Template inheritance for component class hierarchies (Angular can inherit behavior, but not templates)
- Reusable markup helpers that emit Angular template syntax (bindings/directives) consistently across the app
- Lightweight components where you want markup reuse without runtime component behavior
Detailed use cases (with examples) live in docs/index.md.
npm install tshtml tshtml-loader- Add a rule for
.tshtmlfiles withtshtml-loader - Author templates as
.tshtmlmodules exporting a default template - The loader produces HTML at build time; no runtime dependency is added
// hello.tshtml
export default `<p>Hello world!</p>`;import { html } from "tshtml";
export default html`
<div class="card">
<h1>{{ title }}</h1>
<p>{{ body }}</p>
</div>
`;import { html } from "tshtml";
const showCta = true; // build-time feature flag or config
export default html`
<section class="panel">
<h2>Dashboard</h2>
<p *ngFor="let item of items">{{ item }}</p>
${showCta ? html`<button class="primary" (click)="continue()">Continue</button>` : ""}
</section>
`;import { html } from "tshtml";
function hero({ subtitle }: { subtitle?: string }) {
return html`
<header class="hero">
<h1>${"Welcome"}</h1>
${subtitle ? html`<p class="sub">${subtitle}</p>` : ""}
</header>
`;
}
export default hero({ subtitle: "Build-time templates" });import { tag, div, span, cssClass, expr } from "tshtml";
const classes = cssClass("card primary");
classes.addClass("interactive");
export default div(
{ class: classes },
tag("h2", "Title"),
tag("p", { style: { color: "red", fontSize: "14px" } }, "Body"),
tag("button", { onclick: expr("handleClick()") }, "Click")
);- Prefer
htmlfor readability when authoring markup-like templates. - Use
tagwhen you need to construct elements programmatically (e.g., loops that build deeply nested trees, or when working outside template literals).
import { tag } from "tshtml";
const columns = [
{ header: "Name", field: "name" },
{ header: "Email", field: "email" },
];
// Build-time loop over `columns`, emitting an Angular runtime `*ngFor`.
const table = tag(
"table",
tag("thead",
tag("tr", columns.map(c => tag("th", c.header)))
),
tag("tbody",
tag("tr", { "*ngFor": "let row of rows" },
columns.map(c => tag("td", `{{ row.${c.field} }}`))
)
)
);
export default table;cssClass(...)manages class lists safely (addClass,removeClass,render())expr(...)wraps values that should be emitted as JavaScript expressions (not quoted)
Use transformAttrs to map component-style props to HTML attributes, with renaming, defaults, and value transforms:
import { transformAttrs } from "tshtml";
const attrs = transformAttrs(
{ href: "/home", ngIf: "isReady" },
{ ngIf: "ng-if", ngShow: { to: "ng-show", default: false } }
);
// Resulting attrs object:
// { href: "/home", "ng-if": "isReady", "ng-show": false }If you are using tshtml outside Angular (or in tests), you can render builder output to a plain HTML string:
import { tag, tagToString } from "tshtml";
const html = tagToString(tag("div", { class: "box" }, "Content"));
// => '<div class="box">Content</div>'The tshtml-loader package ships a small CLI called tshtml-to-html that executes one or more .tshtml files and writes the resulting HTML.
Compile a single .tshtml next to the source file:
npx tshtml-to-html ./path/to/file.tshtmlPrint the rendered HTML to stdout:
npx tshtml-to-html ./path/to/file.tshtml --stdoutCompile multiple files in one command:
npx tshtml-to-html file1.tshtml file2.tshtml subdir/template.tshtmlNotes:
- Only
.tshtmlinputs are accepted. --stdoutonly works for a single input file.- Output files are written as
inputName.htmlalongside each input.
In Angular projects, you typically don’t need this CLI: Angular consumes the compiled template string produced by the webpack loader.
- Ensure the template exports
default - Self-closing HTML tags are auto-handled (
<img />,<br />, etc.) - Style objects must be plain key-value pairs (
{ color: "red", fontSize: "14px" }) - For boolean attributes, use
EmptyAttributeto emit the attribute without a value