Canonical invoice recipe using the Tiered Composition pattern.
Exposes three levels of composability:
document/2— Batteries-included; returns a fully assembled`%Rendro.Document{}` ready for `Rendro.render/1`.page_template/1— Layout only; returns the%Rendro.PageTemplate{}.sections/2— Content only; returns a list of%Rendro.Section{}structs mapped to named regions.
Usage
Zero-to-one (just works)
data = %{id: "INV-001", date: ~D[2026-01-15], items: [...]}
doc = Rendro.Recipes.Invoice.document(data)
{:ok, pdf} = Rendro.render(doc)Escape hatch — inject a custom template
template = Rendro.Recipes.Invoice.page_template(name: :branded)
sections = Rendro.Recipes.Invoice.sections(data)
doc =
Rendro.Document.new()
|> Rendro.Document.add_template(template)
|> Rendro.Document.set_template(:branded)
|> then(fn d -> Enum.reduce(sections, d, &Rendro.Document.add_section(&2, &1)) end)
Summary
Functions
Assembles and returns a fully composed %Rendro.Document{} using the
pipeline builder API.
Returns a %Rendro.PageTemplate{} with three named regions: :header, :body, :footer.
Returns a list of %Rendro.Section{} structs mapping invoice content to
the :header, :body, and :footer regions.
Functions
@spec document( map(), keyword() ) :: Rendro.Document.t()
Assembles and returns a fully composed %Rendro.Document{} using the
pipeline builder API.
Uses page_template/1 and sections/2 internally, then chains them
through Rendro.Document.new/0 |> add_template |> set_template |> add_section.
Examples
iex> data = %{id: "INV-001", date: ~D[2026-01-15], items: []}
iex> doc = Rendro.Recipes.Invoice.document(data)
iex> doc.page_template
:invoice
@spec page_template(keyword()) :: Rendro.PageTemplate.t()
Returns a %Rendro.PageTemplate{} with three named regions: :header, :body, :footer.
Options
All options are forwarded to %Rendro.PageTemplate{} as keyword overrides.
The name defaults to :invoice.
Examples
iex> Rendro.Recipes.Invoice.page_template()
%Rendro.PageTemplate{name: :invoice, ...}
iex> Rendro.Recipes.Invoice.page_template(name: :branded)
%Rendro.PageTemplate{name: :branded, ...}
@spec sections( map(), keyword() ) :: [Rendro.Section.t()]
Returns a list of %Rendro.Section{} structs mapping invoice content to
the :header, :body, and :footer regions.
Examples
iex> data = %{id: "INV-001", date: ~D[2026-01-15], items: []}
iex> [header, body, footer] = Rendro.Recipes.Invoice.sections(data)
iex> header.region
:header