jonnifyelixir
F6 · Phoenix Framework / F6.05 · heex

F6 · the architecture · module 5

Templates, components & HEEx

F6.01 ended with a controller returning a response; HEEx is how that response becomes HTML. HEEx — HTML+EEx, written in the ~H sigil or a .html.heex file — is a template language that compiles to a structure the server can render and, later, diff. A template is a pure function of its assigns: the controller sets @courses from data the Catalog context exposed, and the template renders it with :for, :if, and curly interpolation. Repeated markup becomes a function component — a function from assigns to markup, declared with attr and slot so its inputs are checked at compile time. And a form is a changeset turned into a form, so the F6.03 validation surfaces as inline errors and the submitted params flow back to the context. HEEx also escapes interpolated values by default, which closes the most common injection hole without any ceremony.

Three dives: templates and the assigns they render, function components and slots, and changeset-backed forms — the view half of everything the controllers and contexts already built.

Assigns render into markup

ASSIGNS @course = %{ title: "Algebra", lessons: 6 } <.course_card course={@course} /> renders RENDERED HTML Algebra 6 lessons

@course = %{title: "Algebra", lessons: 6}
Change one assign and only the markup that reads it re-renders.

Three pieces of the view

The view layer is three things, and this module takes each in turn. A template renders the assigns a controller set. A component is reusable markup with a typed interface. A form is a changeset rendered for editing, with errors and a path back to the domain. Select a piece.

The view layer · select a piece

TEMPLATE ~H sigil / .html.heex — a pure function of @assigns F6.05.1 COMPONENT attr + slot — reusable markup, checked at compile time F6.05.2 FORM to_form(changeset) — F6.03 validation, rendered with errors F6.05.3

piece: Template

is: render the assigns

HEEx is not a string templating language with holes punched in it. It compiles to a structure that separates the static markup from the dynamic assigns, which is what lets the same templates power LiveView’s diffing in F6.06 without a rewrite.

Where the view sits

The view does not reach for data — it receives it. A controller (F6.01) calls the Portal facade, gets back structs from a context (F6.04), and assigns them; the HEEx template renders those assigns, composing function components as it goes; the result is HTML in the response. Reading left to right, the only arrow into the template is assigns, never a query.

facade → assigns → HEEx → HTML

Portal facade context structs controller assign @courses assigns HEEx template pure fn of @assigns <.course_card /> components HTML in the response the template receives assigns and renders — it never queries the database

Keeping data access out of the template is the same discipline as the context boundary, one layer up: the controller fetches, the view renders. A query in a template couples markup to storage and defeats both.

Three deep dives

In order: templates and the assigns they render; function components and slots for reuse; and forms backed by changesets.

F6.05.1
Templates & assigns
The ~H sigil, rendering @assigns with :for and :if, curly interpolation, and verified ~p routes.
F6.05.2
Function components & slots
attr and slot, a reusable <.course_card>, and render_slot/1 for wrapping content.
F6.05.3
Forms & inputs
to_form/1 over a changeset, <.form> and <.input>, and F6.03 errors shown inline.

F6.01 returned

a response — the controller’s last act was render/2 with assigns.

F6.05 renders it

HEEx turns those assigns into HTML, composing components and forms.

Start with templates and assigns, then function components and slots, then forms and inputs. This module follows F6.04 — contexts — and the next, F6.06, makes these same templates live with LiveView.

References

HEEx, function components, and forms in reference form.

Sources

Related in this course