Files
skills/docs/communication/emails/email-templates/src/template-builder/template-builder.md
2026-05-29 08:20:56 +01:00

3.2 KiB

template-builder

(no submodules)

Purpose

TemplateBuilder is a fluent API for assembling an EmailTemplate<TProps> value step-by-step. It exists because constructing the template literal inline reads poorly when defaults and subject functions are non-trivial, and because the builder enforces presence of the three required fields (name, subject, component) at build() time with a typed error.

The class itself is a typical builder — each setter mutates the internal state and returns this. build() is the one terminal operation. Calls made after build() continue to work (the builder is not consumed), so a single builder can produce two slightly-different templates by switching one setter and calling build() twice.

Features

  • Fluent setters: name, subject (literal or function-of-props), component, defaultProps.
  • Runtime validation in build() — missing required fields raise EmailTemplatesError(INVALID_TEMPLATE) with a specific message key.
  • createTemplateBuilder<TProps>() factory for inference-friendly use.

Usage: Basic

import { createTemplateBuilder } from "@suaveplan/email-templates/template-builder";
import { h } from "@suaveplan/email-templates/vnode";

interface Props { name: string; ctaUrl: string }

const myTemplate = createTemplateBuilder<Props>()
  .name("custom-welcome")
  .subject((p) => `Hi ${p.name}`)
  .component((p) => h("a", { href: p.ctaUrl }, "Click me"))
  .build();

Usage: Advanced

Reuse a single builder to produce a localised template family by mutating between build() calls:

import { createTemplateBuilder } from "@suaveplan/email-templates/template-builder";
import { h } from "@suaveplan/email-templates/vnode";

interface Props { name: string }

const b = createTemplateBuilder<Props>()
  .component((p) => h("p", {}, `Hi ${p.name}`));

const en = b.name("greet-en").subject("Hello").build();
const fr = b.name("greet-fr").subject("Bonjour").build();

en.subject === "Hello" and fr.subject === "Bonjour" — the builder returns a fresh EmailTemplate object on each build() call.

API Reference

Symbol Kind Description
TemplateBuilder<T> class The builder itself; instance methods are chainable.
createTemplateBuilder function <T>() => TemplateBuilder<T> factory.
TemplateBuilderApi<T> type The interface implemented by TemplateBuilder<T>.
EmailComponentFn<T> type (props: T & { theme?; clock? }) => VNode.

Implementation Notes

The builder never throws inside a setter — invariants are checked exclusively in build(). Empty-string name is treated as missing (consistent with upstream behaviour). The defaultProps field is optional; omitting it leaves it undefined on the produced template.

Because build() returns a fresh object every time, callers can mutate the builder and reuse it for closely-related templates — useful for i18n where the body component is identical and only the subject text changes by locale.