"form_for" vs. ".form" vs "f = form_for"

In various code samples, I see different ways to create a form in a .heex template.

What is the difference between using the following:

<%= form_for @changeset, "/to_path", ...other_opts, fn f -> %>
<% end %>
<%= f = form_for @changeset, "to_path, ...other_opts %>
<% end %>
<.form let={f} for={@changeset} action={"to_path"} ...other_opts>

Is there a best practice, or is it just up to the preferences of the developer?

I found some answers in the Phoenix.HTML docs:

  1. <%= f = form_for @changeset ... %> is now deprecated. Use <%= form_for @changeset ... %> instead.

  2. <.form> is a “function component”, in the context of Phoenix LiveViews.

This leads me to a follow-up question: If I don’t use LiveViews, should I still use <.form>?

You’re right about the difference. According to the LiveView docs, <.form> is just a wrapper around form_for and should generally be preferred if you’re using HEEx templates (including on deadviews). Just remember to give the action attribute!

See Phoenix.LiveView.Helpers documentation under “Outside LiveView”