Phoenix HTML / HEEx Template Guidelines
Template Format
- •Phoenix templates always use
~Hor .html.heex files (known as HEEx), never use~E
Forms
- •Always use the imported
Phoenix.Component.form/1andPhoenix.Component.inputs_for/1function to build forms. Never usePhoenix.HTML.form_fororPhoenix.HTML.inputs_foras they are outdated - •When building forms always use the already imported
Phoenix.Component.to_form/2:
assign(socket, form: to_form(...))
<.form for={@form} id="msg-form">
<.input field={@form[:content]} type="text" />
</.form>
- •Always add unique DOM IDs to key elements (like forms, buttons, etc) when writing templates - these IDs can later be used in tests
App-Wide Template Imports
- •For "app wide" template imports, you can import/alias into the
your_app_web.ex'shtml_helpersblock, so they will be available to all LiveViews, LiveComponents, and all modules that douse YourAppWeb, :html
Conditional Rendering
- •Elixir supports
if/elsebut does NOT supportif/else iforif/elsif. **Never useelse iforelseifin Elixir**, **always** usecondorcase` for multiple conditionals:
<%!-- NEVER do this (invalid) --%>
<%= if condition do %>
...
<% else if other_condition %>
...
<% end %>
<%!-- ALWAYS do this --%>
<%= cond do %>
<% condition -> %>
...
<% condition2 -> %>
...
<% true -> %>
...
<% end %>
Literal Curly Braces
HEEx require special tag annotation if you want to insert literal curly braces. For code snippets in <pre> or <code> blocks, annotate the parent tag with phx-no-curly-interpolation:
<code phx-no-curly-interpolation>
let obj = {key: "val"}
</code>
Within annotated tags, you can use { and } without escaping, and dynamic Elixir expressions can still be used with <%= ... %> syntax.
Class Lists
HEEx class attrs support lists, but you must always use list [...] syntax. Use the class list syntax to conditionally add classes:
<a class={[
"px-2 text-white",
@some_flag && "py-5",
if(@other_condition, do: "border-red-500", else: "border-blue-100"),
]}>Text</a>
Always wrap if's inside {...} expressions with parens.
Never do this (missing [ and ]):
<%!-- INVALID --%>
<a class={
"px-2 text-white",
@some_flag && "py-5"
}> ...
Iteration
- •Never use
<% Enum.each %>or non-for comprehensions for generating template content, instead always use<%= for item <- @collection do %>
Comments
- •HEEx HTML comments use
<%!-- comment --%>. Always use this syntax for template comments
Interpolation
HEEx allows interpolation via {...} and <%= ... %>, but the <%= %> only works within tag bodies.
Always do this:
<div id={@id}>
{@my_assign}
<%= if @some_block_condition do %>
{@another_assign}
<% end %>
</div>
Never do this (syntax error):
<%!-- THIS IS INVALID --%>
<div id="<%= @invalid_interpolation %>">
{if @invalid_block_construct do}
{end}
</div>
Rules:
- •Use
{...}for interpolation within tag attributes - •Use
{...}for interpolation of values within tag bodies - •Use
<%= ... %>for block constructs (if, cond, case, for) within tag bodies