Repository: phoenixframework/phoenix
Pull request #5972 (2024-11-09 18:03:38)

Set gzip default based on code reloading in endpoint
Adjust the default for the gzip flag in the generated endpoint to take
code reloading into account.

Fixes phoenixframework/phoenix#5960


Patch:
diff --git a/installer/templates/phx_assets/app.js b/installer/templates/phx_assets/app.js
index 0d9f8cdd1..a5848b2cb 100644
--- a/installer/templates/phx_assets/app.js
+++ b/installer/templates/phx_assets/app.js
@@ -22,8 +22,8 @@ import "phoenix_html"
 <%= @live_comment %>import {LiveSocket} from "phoenix_live_view"
 <%= @live_comment %>import topbar from "../vendor/topbar"
 
-<%= @live_comment %>let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
-<%= @live_comment %>let liveSocket = new LiveSocket("/live", Socket, {
+<%= @live_comment %>const csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
+<%= @live_comment %>const liveSocket = new LiveSocket("/live", Socket, {
 <%= @live_comment %>  longPollFallbackMs: 2500,
 <%= @live_comment %>  params: {_csrf_token: csrfToken}
 <%= @live_comment %>})
@@ -41,4 +41,39 @@ import "phoenix_html"
 // >> liveSocket.enableLatencySim(1000)  // enabled for duration of browser session
 // >> liveSocket.disableLatencySim()
 <%= @live_comment %>window.liveSocket = liveSocket
+
+// Uncomment the lines below to enable quality of life phoenix_live_reload
+// development features:
+//
+//     1. stream server logs to the browser console
+//     2. click on elements to jump to their definitions in your code editor
+//
+// if (process.env.NODE_ENV === "development") {
+//   window.addEventListener("phx:live_reload:attached", ({detail: reloader}) => {
+//     // Enable server log streaming to client.
+//     // Disable with reloader.disableServerLogs()
+//     reloader.enableServerLogs()
+//
+//     // Open configured PLUG_EDITOR at file:line of the clicked element's HEEx component
+//     //
+//     //   * click with "c" key pressed to open at caller location
+//     //   * click with "d" key pressed to open at function component definition location
+//     let keyDown
+//     window.addEventListener("keydown", e => keyDown = e.key)
+//     window.addEventListener("keyup", e => keyDown = null)
+//     window.addEventListener("click", e => {
+//       if(keyDown === "c"){
+//         e.preventDefault()
+//         e.stopImmediatePropagation()
+//         reloader.openEditorAtCaller(e.target)
+//       } else if(keyDown === "d"){
+//         e.preventDefault()
+//         e.stopImmediatePropagation()
+//         reloader.openEditorAtDef(e.target)
+//       }
+//     }, true)
+//
+//     window.liveReloader = reloader
+//   })
+// }
 <% end %>
diff --git a/installer/templates/phx_single/README.md b/installer/templates/phx_single/README.md
index 5c96eb63a..304d84424 100644
--- a/installer/templates/phx_single/README.md
+++ b/installer/templates/phx_single/README.md
@@ -2,8 +2,8 @@
 
 To start your Phoenix server:
 
-  * Run `mix setup` to install and setup dependencies
-  * Start Phoenix endpoint with `mix phx.server` or inside IEx with `iex -S mix phx.server`
+* Run `mix setup` to install and setup dependencies
+* Start Phoenix endpoint with `mix phx.server` or inside IEx with `iex -S mix phx.server`
 
 Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.
 
@@ -11,8 +11,8 @@ Ready to run in production? Please [check our deployment guides](https://hexdocs
 
 ## Learn more
 
-  * Official website: https://www.phoenixframework.org/
-  * Guides: https://hexdocs.pm/phoenix/overview.html
-  * Docs: https://hexdocs.pm/phoenix
-  * Forum: https://elixirforum.com/c/phoenix-forum
-  * Source: https://github.com/phoenixframework/phoenix
+* Official website: https://www.phoenixframework.org/
+* Guides: https://hexdocs.pm/phoenix/overview.html
+* Docs: https://hexdocs.pm/phoenix
+* Forum: https://elixirforum.com/c/phoenix-forum
+* Source: https://github.com/phoenixframework/phoenix
diff --git a/installer/templates/phx_single/config/dev.exs b/installer/templates/phx_single/config/dev.exs
index 4dc897f64..3df396383 100644
--- a/installer/templates/phx_single/config/dev.exs
+++ b/installer/templates/phx_single/config/dev.exs
@@ -45,6 +45,7 @@ config :<%= @app_name %>, <%= @endpoint_module %>,
 # Watch static and templates for browser reloading.
 config :<%= @app_name %>, <%= @endpoint_module %>,
   live_reload: [
+    web_console_logger: true,
     patterns: [
       ~r"priv/static/(?!uploads/).*(js|css|png|jpeg|jpg|gif|svg)$",<%= if @gettext do %>
       ~r"priv/gettext/.*(po)$",<% end %>
diff --git a/installer/templates/phx_umbrella/apps/app_name_web/README.md b/installer/templates/phx_umbrella/apps/app_name_web/README.md
index fdb87dfcf..3d9845a58 100644
--- a/installer/templates/phx_umbrella/apps/app_name_web/README.md
+++ b/installer/templates/phx_umbrella/apps/app_name_web/README.md
@@ -2,8 +2,8 @@
 
 To start your Phoenix server:
 
-  * Run `mix setup` to install and setup dependencies
-  * Start Phoenix endpoint with `mix phx.server`
+* Run `mix setup` to install and setup dependencies
+* Start Phoenix endpoint with `mix phx.server`
 
 Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.
 
@@ -11,8 +11,8 @@ Ready to run in production? Please [check our deployment guides](https://hexdocs
 
 ## Learn more
 
-  * Official website: https://www.phoenixframework.org/
-  * Guides: https://hexdocs.pm/phoenix/overview.html
-  * Docs: https://hexdocs.pm/phoenix
-  * Forum: https://elixirforum.com/c/phoenix-forum
-  * Source: https://github.com/phoenixframework/phoenix
+* Official website: https://www.phoenixframework.org/
+* Guides: https://hexdocs.pm/phoenix/overview.html
+* Docs: https://hexdocs.pm/phoenix
+* Forum: https://elixirforum.com/c/phoenix-forum
+* Source: https://github.com/phoenixframework/phoenix
diff --git a/installer/templates/phx_umbrella/apps/app_name_web/config/dev.exs b/installer/templates/phx_umbrella/apps/app_name_web/config/dev.exs
index bcc1304b4..d73204be7 100644
--- a/installer/templates/phx_umbrella/apps/app_name_web/config/dev.exs
+++ b/installer/templates/phx_umbrella/apps/app_name_web/config/dev.exs
@@ -45,6 +45,7 @@ config :<%= @web_app_name %>, <%= @endpoint_module %>,
 # Watch static and templates for browser reloading.
 config :<%= @web_app_name %>, <%= @endpoint_module %>,
   live_reload: [
+    web_console_logger: true,
     patterns: [
       ~r"priv/static/(?!uploads/).*(js|css|png|jpeg|jpg|gif|svg)$",<%= if @gettext do %>
       ~r"priv/gettext/.*(po)$",<% end %>
diff --git a/installer/templates/phx_web/components/core_components.ex b/installer/templates/phx_web/components/core_components.ex
index 1aa9858b7..c604ef553 100644
--- a/installer/templates/phx_web/components/core_components.ex
+++ b/installer/templates/phx_web/components/core_components.ex
@@ -76,7 +76,7 @@ defmodule <%= @web_namespace %>.CoreComponents do
 
   def flash_group(assigns) do
     ~H"""
-    <div id={@id}>
+    <div id={@id} aria-live="polite">
       <.flash kind={:info} title=<%= maybe_heex_attr_gettext.("Success!", @gettext) %> flash={@flash} />
       <.flash kind={:error} title=<%= maybe_heex_attr_gettext.("Error!", @gettext) %> flash={@flash} />
       <.flash
@@ -120,7 +120,7 @@ defmodule <%= @web_namespace %>.CoreComponents do
       </.simple_form>
   """
   attr :for, :any, required: true, doc: "the data structure for the form"
-  attr :as, :any, default: nil, doc: "the server side parameter to collect all input under"
+  attr :as, :any, doc: "the server side parameter to collect all input under"
 
   attr :rest, :global,
     include: ~w(autocomplete name rel action enctype method novalidate target multipart),
@@ -130,8 +130,10 @@ defmodule <%= @web_namespace %>.CoreComponents do
   slot :actions, doc: "the slot for form actions, such as a submit button"
 
   def simple_form(assigns) do
+    assigns = assign(assigns, :as, if(assigns[:as], do: %{as: assigns[:as]}, else: %{}))
+
     ~H"""
-    <.form :let={f} for={@for} as={@as} {@rest}>
+    <.form :let={f} for={@for} {@as} {@rest}>
       <div class="mt-10 space-y-8 bg-white">
         <%%= render_slot(@inner_block, f) %>
         <div :for={action <- @actions} class="mt-2 flex items-center justify-between gap-6">
diff --git a/installer/templates/phx_web/endpoint.ex b/installer/templates/phx_web/endpoint.ex
index f14b4d97b..4b37bf5bc 100644
--- a/installer/templates/phx_web/endpoint.ex
+++ b/installer/templates/phx_web/endpoint.ex
@@ -17,12 +17,13 @@ defmodule <%= @endpoint_module %> do
 
   # Serve at "/" the static files from "priv/static" directory.
   #
-  # You should set gzip to true if you are running phx.digest
-  # when deploying your static files in production.
+  # When code reloading is disabled (e.g., in production),
+  # the `gzip` option is enabled to serve compressed
+  # static files generated by running `phx.digest`.
   plug Plug.Static,
     at: "/",
     from: :<%= @web_app_name %>,
-    gzip: false,
+    gzip: not code_reloading?,
     only: <%= @web_namespace %>.static_paths()
 
   # Code reloading can be explicitly enabled under the
diff --git a/lib/mix/tasks/phx.gen.auth.ex b/lib/mix/tasks/phx.gen.auth.ex
index 4e2910573..04cb5d234 100644
--- a/lib/mix/tasks/phx.gen.auth.ex
+++ b/lib/mix/tasks/phx.gen.auth.ex
@@ -274,69 +274,91 @@ defmodule Mix.Tasks.Phx.Gen.Auth do
     case Keyword.fetch(context.opts, :live) do
       {:ok, true} ->
         live_files = [
-          "registration_live.ex": [web_pre, "live", web_path, "#{singular}_registration_live.ex"],
+          "registration_live.ex": [
+            web_pre,
+            "live",
+            web_path,
+            "#{singular}_live",
+            "registration.ex"
+          ],
           "registration_live_test.exs": [
             web_test_pre,
             "live",
             web_path,
-            "#{singular}_registration_live_test.exs"
+            "#{singular}_live",
+            "registration_test.exs"
           ],
-          "login_live.ex": [web_pre, "live", web_path, "#{singular}_login_live.ex"],
+          "login_live.ex": [web_pre, "live", web_path, "#{singular}_live", "login.ex"],
           "login_live_test.exs": [
             web_test_pre,
             "live",
             web_path,
-            "#{singular}_login_live_test.exs"
+            "#{singular}_live",
+            "login_test.exs"
           ],
           "reset_password_live.ex": [
             web_pre,
             "live",
             web_path,
-            "#{singular}_reset_password_live.ex"
+            "#{singular}_live",
+            "reset_password.ex"
           ],
           "reset_password_live_test.exs": [
             web_test_pre,
             "live",
             web_path,
-            "#{singular}_reset_password_live_test.exs"
+            "#{singular}_live",
+            "reset_password_test.exs"
           ],
           "forgot_password_live.ex": [
             web_pre,
             "live",
             web_path,
-            "#{singular}_forgot_password_live.ex"
+            "#{singular}_live",
+            "forgot_password.ex"
           ],
           "forgot_password_live_test.exs": [
             web_test_pre,
             "live",
             web_path,
-            "#{singular}_forgot_password_live_test.exs"
+            "#{singular}_live",
+            "forgot_password_test.exs"
           ],
-          "settings_live.ex": [web_pre, "live", web_path, "#{singular}_settings_live.ex"],
+          "settings_live.ex": [web_pre, "live", web_path, "#{singular}_live", "settings.ex"],
           "settings_live_test.exs": [
             web_test_pre,
             "live",
             web_path,
-            "#{singular}_settings_live_test.exs"
+            "#{singular}_live",
+            "settings_test.exs"
+          ],
+          "confirmation_live.ex": [
+            web_pre,
+            "live",
+            web_path,
+            "#{singular}_live",
+            "confirmation.ex"
           ],
-          "confirmation_live.ex": [web_pre, "live", web_path, "#{singular}_confirmation_live.ex"],
           "confirmation_live_test.exs": [
             web_test_pre,
             "live",
             web_path,
-            "#{singular}_confirmation_live_test.exs"
+            "#{singular}_live",
+            "confirmation_test.exs"
           ],
           "confirmation_instructions_live.ex": [
             web_pre,
             "live",
             web_path,
-            "#{singular}_confirmation_instructions_live.ex"
+            "#{singular}_live",
+            "confirmation_instructions.ex"
           ],
           "confirmation_instructions_live_test.exs": [
             web_test_pre,
             "live",
             web_path,
-            "#{singular}_confirmation_instructions_live_test.exs"
+            "#{singular}_live",
+            "confirmation_instructions_test.exs"
           ]
         ]
 
diff --git a/lib/mix/tasks/phx.gen.auth/injector.ex b/lib/mix/tasks/phx.gen.auth/injector.ex
index 90a2116c8..48ae16782 100644
--- a/lib/mix/tasks/phx.gen.auth/injector.ex
+++ b/lib/mix/tasks/phx.gen.auth/injector.ex
@@ -161,7 +161,7 @@ defmodule Mix.Tasks.Phx.Gen.Auth.Injector do
   Menu code to inject into the application layout template.
   """
   def app_layout_menu_code_to_inject(%Schema{} = schema, padding \\ 4, newline \\ "\n") do
-    already_injected_str = "#{schema.route_prefix}/log_in"
+    already_injected_str = "#{schema.route_prefix}/log-in"
 
     base_tailwind_classes = "text-[0.8125rem] leading-6 text-zinc-900"
     link_tailwind_classes = "#{base_tailwind_classes} font-semibold hover:text-zinc-700"
@@ -182,7 +182,7 @@ defmodule Mix.Tasks.Phx.Gen.Auth.Injector do
         </li>
         <li>
           <.link
-            href={~p"#{schema.route_prefix}/log_out"}
+            href={~p"#{schema.route_prefix}/log-out"}
             method="delete"
             class="#{link_tailwind_classes}"
           >
@@ -200,7 +200,7 @@ defmodule Mix.Tasks.Phx.Gen.Auth.Injector do
         </li>
         <li>
           <.link
-            href={~p"#{schema.route_prefix}/log_in"}
+            href={~p"#{schema.route_prefix}/log-in"}
             class="#{link_tailwind_classes}"
           >
             Log in
diff --git a/lib/mix/tasks/phx.gen.html.ex b/lib/mix/tasks/phx.gen.html.ex
index b435d3a4d..76fe2aa38 100644
--- a/lib/mix/tasks/phx.gen.html.ex
+++ b/lib/mix/tasks/phx.gen.html.ex
@@ -198,7 +198,7 @@ defmodule Mix.Tasks.Phx.Gen.Html do
         ~s(<.input field={f[#{inspect(key)}]} type="checkbox" label="#{label(key)}" />)
 
       {key, :text} ->
-        ~s(<.input field={f[#{inspect(key)}]} type="text" label="#{label(key)}" />)
+        ~s(<.input field={f[#{inspect(key)}]} type="textarea" label="#{label(key)}" />)
 
       {key, :date} ->
         ~s(<.input field={f[#{inspect(key)}]} type="date" label="#{label(key)}" />)
diff --git a/lib/mix/tasks/phx.gen.live.ex b/lib/mix/tasks/phx.gen.live.ex
index 59a51514d..f0b6aa28a 100644
--- a/lib/mix/tasks/phx.gen.live.ex
+++ b/lib/mix/tasks/phx.gen.live.ex
@@ -285,7 +285,7 @@ defmodule Mix.Tasks.Phx.Gen.Live do
         ~s(<.input field={@form[#{inspect(key)}]} type="checkbox" label="#{label(key)}" />)
 
       {key, :text} ->
-        ~s(<.input field={@form[#{inspect(key)}]} type="text" label="#{label(key)}" />)
+        ~s(<.input field={@form[#{inspect(key)}]} type="textarea" label="#{label(key)}" />)
 
       {key, :date} ->
         ~s(<.input field={@form[#{inspect(key)}]} type="date" label="#{label(key)}" />)
diff --git a/priv/templates/phx.gen.auth/auth.ex b/priv/templates/phx.gen.auth/auth.ex
index 472a0214c..af36929d2 100644
--- a/priv/templates/phx.gen.auth/auth.ex
+++ b/priv/templates/phx.gen.auth/auth.ex
@@ -158,7 +158,7 @@ defmodule <%= inspect auth_module %> do
       socket =
         socket
         |> Phoenix.LiveView.put_flash(:error, "You must log in to access this page.")
-        |> Phoenix.LiveView.redirect(to: ~p"<%= schema.route_prefix %>/log_in")
+        |> Phoenix.LiveView.redirect(to: ~p"<%= schema.route_prefix %>/log-in")
 
       {:halt, socket}
     end
@@ -208,7 +208,7 @@ defmodule <%= inspect auth_module %> do
       conn
       |> put_flash(:error, "You must log in to access this page.")
       |> maybe_store_return_to()
-      |> redirect(to: ~p"<%= schema.route_prefix %>/log_in")
+      |> redirect(to: ~p"<%= schema.route_prefix %>/log-in")
       |> halt()
     end
   end
diff --git a/priv/templates/phx.gen.auth/confirmation_edit.html.heex b/priv/templates/phx.gen.auth/confirmation_edit.html.heex
index d509deedf..0f6d96d41 100644
--- a/priv/templates/phx.gen.auth/confirmation_edit.html.heex
+++ b/priv/templates/phx.gen.auth/confirmation_edit.html.heex
@@ -9,6 +9,6 @@
 
   <p :if={!@current_<%= schema.singular %>} class="text-center mt-4">
     <.link href={~p"<%= schema.route_prefix %>/register"}>Register</.link>
-    | <.link href={~p"<%= schema.route_prefix %>/log_in"}>Log in</.link>
+    | <.link href={~p"<%= schema.route_prefix %>/log-in"}>Log in</.link>
   </p>
 </div>
diff --git a/priv/templates/phx.gen.auth/confirmation_instructions_live.ex b/priv/templates/phx.gen.auth/confirmation_instructions_live.ex
index 8752927ad..ac8d9b298 100644
--- a/priv/templates/phx.gen.auth/confirmation_instructions_live.ex
+++ b/priv/templates/phx.gen.auth/confirmation_instructions_live.ex
@@ -1,4 +1,4 @@
-defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>ConfirmationInstructionsLive do
+defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.ConfirmationInstructions do
   use <%= inspect context.web_module %>, :live_view
 
   alias <%= inspect context.module %>
@@ -22,7 +22,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
       <p :if={!@current_<%= schema.singular %>} class="text-center mt-4">
         <.link href={~p"<%= schema.route_prefix %>/register"}>Register</.link>
-        | <.link href={~p"<%= schema.route_prefix %>/log_in"}>Log in</.link>
+        | <.link href={~p"<%= schema.route_prefix %>/log-in"}>Log in</.link>
       </p>
     </div>
     """
diff --git a/priv/templates/phx.gen.auth/confirmation_live.ex b/priv/templates/phx.gen.auth/confirmation_live.ex
index 080ef5326..251afacec 100644
--- a/priv/templates/phx.gen.auth/confirmation_live.ex
+++ b/priv/templates/phx.gen.auth/confirmation_live.ex
@@ -1,4 +1,4 @@
-defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>ConfirmationLive do
+defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.Confirmation do
   use <%= inspect context.web_module %>, :live_view
 
   alias <%= inspect context.module %>
@@ -17,7 +17,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
       <p :if={!@current_<%= schema.singular %>} class="text-center mt-4">
         <.link href={~p"<%= schema.route_prefix %>/register"}>Register</.link>
-        | <.link href={~p"<%= schema.route_prefix %>/log_in"}>Log in</.link>
+        | <.link href={~p"<%= schema.route_prefix %>/log-in"}>Log in</.link>
       </p>
     </div>
     """
diff --git a/priv/templates/phx.gen.auth/confirmation_new.html.heex b/priv/templates/phx.gen.auth/confirmation_new.html.heex
index b26b20248..97b952445 100644
--- a/priv/templates/phx.gen.auth/confirmation_new.html.heex
+++ b/priv/templates/phx.gen.auth/confirmation_new.html.heex
@@ -15,6 +15,6 @@
 
   <p :if={!@current_<%= schema.singular %>} class="text-center mt-4">
     <.link href={~p"<%= schema.route_prefix %>/register"}>Register</.link>
-    | <.link href={~p"<%= schema.route_prefix %>/log_in"}>Log in</.link>
+    | <.link href={~p"<%= schema.route_prefix %>/log-in"}>Log in</.link>
   </p>
 </div>
diff --git a/priv/templates/phx.gen.auth/context_functions.ex b/priv/templates/phx.gen.auth/context_functions.ex
index 3d4e25936..e3a2c090f 100644
--- a/priv/templates/phx.gen.auth/context_functions.ex
+++ b/priv/templates/phx.gen.auth/context_functions.ex
@@ -154,7 +154,7 @@
 
   ## Examples
 
-      iex> deliver_<%= schema.singular %>_update_email_instructions(<%= schema.singular %>, current_email, &url(~p"<%= schema.route_prefix %>/settings/confirm_email/#{&1}"))
+      iex> deliver_<%= schema.singular %>_update_email_instructions(<%= schema.singular %>, current_email, &url(~p"<%= schema.route_prefix %>/settings/confirm-email/#{&1}"))
       {:ok, %{to: ..., body: ...}}
 
   """
@@ -288,7 +288,7 @@
 
   ## Examples
 
-      iex> deliver_<%= schema.singular %>_reset_password_instructions(<%= schema.singular %>, &url(~p"<%= schema.route_prefix %>/reset_password/#{&1}"))
+      iex> deliver_<%= schema.singular %>_reset_password_instructions(<%= schema.singular %>, &url(~p"<%= schema.route_prefix %>/reset-password/#{&1}"))
       {:ok, %{to: ..., body: ...}}
 
   """
diff --git a/priv/templates/phx.gen.auth/forgot_password_live.ex b/priv/templates/phx.gen.auth/forgot_password_live.ex
index fb5ba7aa5..dc4a03a59 100644
--- a/priv/templates/phx.gen.auth/forgot_password_live.ex
+++ b/priv/templates/phx.gen.auth/forgot_password_live.ex
@@ -1,4 +1,4 @@
-defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>ForgotPasswordLive do
+defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.ForgotPassword do
   use <%= inspect context.web_module %>, :live_view
 
   alias <%= inspect context.module %>
@@ -21,7 +21,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       </.simple_form>
       <p class="text-center text-sm mt-4">
         <.link href={~p"<%= schema.route_prefix %>/register"}>Register</.link>
-        | <.link href={~p"<%= schema.route_prefix %>/log_in"}>Log in</.link>
+        | <.link href={~p"<%= schema.route_prefix %>/log-in"}>Log in</.link>
       </p>
     </div>
     """
@@ -35,7 +35,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     if <%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>_by_email(email) do
       <%= inspect context.alias %>.deliver_<%= schema.singular %>_reset_password_instructions(
         <%= schema.singular %>,
-        &url(~p"<%= schema.route_prefix %>/reset_password/#{&1}")
+        &url(~p"<%= schema.route_prefix %>/reset-password/#{&1}")
       )
     end
 
diff --git a/priv/templates/phx.gen.auth/login_live.ex b/priv/templates/phx.gen.auth/login_live.ex
index 6a3c28389..e9957f607 100644
--- a/priv/templates/phx.gen.auth/login_live.ex
+++ b/priv/templates/phx.gen.auth/login_live.ex
@@ -1,4 +1,4 @@
-defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>LoginLive do
+defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.Login do
   use <%= inspect context.web_module %>, :live_view
 
   def render(assigns) do
@@ -15,13 +15,13 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
         </:subtitle>
       </.header>
 
-      <.simple_form for={@form} id="login_form" action={~p"<%= schema.route_prefix %>/log_in"} phx-update="ignore">
+      <.simple_form for={@form} id="login_form" action={~p"<%= schema.route_prefix %>/log-in"} phx-update="ignore">
         <.input field={@form[:email]} type="email" label="Email" required />
         <.input field={@form[:password]} type="password" label="Password" required />
 
         <:actions>
           <.input field={@form[:remember_me]} type="checkbox" label="Keep me logged in" />
-          <.link href={~p"<%= schema.route_prefix %>/reset_password"} class="text-sm font-semibold">
+          <.link href={~p"<%= schema.route_prefix %>/reset-password"} class="text-sm font-semibold">
             Forgot your password?
           </.link>
         </:actions>
diff --git a/priv/templates/phx.gen.auth/registration_live.ex b/priv/templates/phx.gen.auth/registration_live.ex
index 3f7f422fe..f5c5ef830 100644
--- a/priv/templates/phx.gen.auth/registration_live.ex
+++ b/priv/templates/phx.gen.auth/registration_live.ex
@@ -1,4 +1,4 @@
-defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>RegistrationLive do
+defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.Registration do
   use <%= inspect context.web_module %>, :live_view
 
   alias <%= inspect context.module %>
@@ -11,7 +11,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
         Register for an account
         <:subtitle>
           Already registered?
-          <.link navigate={~p"<%= schema.route_prefix %>/log_in"} class="font-semibold text-brand hover:underline">
+          <.link navigate={~p"<%= schema.route_prefix %>/log-in"} class="font-semibold text-brand hover:underline">
             Log in
           </.link>
           to your account now.
@@ -24,7 +24,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
         phx-submit="save"
         phx-change="validate"
         phx-trigger-action={@trigger_submit}
-        action={~p"<%= schema.route_prefix %>/log_in?_action=registered"}
+        action={~p"<%= schema.route_prefix %>/log-in?_action=registered"}
         method="post"
       >
         <.error :if={@check_errors}>
diff --git a/priv/templates/phx.gen.auth/registration_new.html.heex b/priv/templates/phx.gen.auth/registration_new.html.heex
index 6f036442e..ae1c5fbb8 100644
--- a/priv/templates/phx.gen.auth/registration_new.html.heex
+++ b/priv/templates/phx.gen.auth/registration_new.html.heex
@@ -3,7 +3,7 @@
     Register for an account
     <:subtitle>
       Already registered?
-      <.link navigate={~p"<%= schema.route_prefix %>/log_in"} class="font-semibold text-brand hover:underline">
+      <.link navigate={~p"<%= schema.route_prefix %>/log-in"} class="font-semibold text-brand hover:underline">
         Log in
       </.link>
       to your account now.
diff --git a/priv/templates/phx.gen.auth/reset_password_controller.ex b/priv/templates/phx.gen.auth/reset_password_controller.ex
index 5dc1c60fc..e572e4d5f 100644
--- a/priv/templates/phx.gen.auth/reset_password_controller.ex
+++ b/priv/templates/phx.gen.auth/reset_password_controller.ex
@@ -13,7 +13,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     if <%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>_by_email(email) do
       <%= inspect context.alias %>.deliver_<%= schema.singular %>_reset_password_instructions(
         <%= schema.singular %>,
-        &url(~p"<%= schema.route_prefix %>/reset_password/#{&1}")
+        &url(~p"<%= schema.route_prefix %>/reset-password/#{&1}")
       )
     end
 
@@ -36,7 +36,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       {:ok, _} ->
         conn
         |> put_flash(:info, "Password reset successfully.")
-        |> redirect(to: ~p"<%= schema.route_prefix %>/log_in")
+        |> redirect(to: ~p"<%= schema.route_prefix %>/log-in")
 
       {:error, changeset} ->
         render(conn, :edit, changeset: changeset)
diff --git a/priv/templates/phx.gen.auth/reset_password_edit.html.heex b/priv/templates/phx.gen.auth/reset_password_edit.html.heex
index a4699b854..29615463d 100644
--- a/priv/templates/phx.gen.auth/reset_password_edit.html.heex
+++ b/priv/templates/phx.gen.auth/reset_password_edit.html.heex
@@ -3,7 +3,7 @@
     Reset Password
   </.header>
 
-  <.simple_form :let={f} for={@changeset} action={~p"<%= schema.route_prefix %>/reset_password/#{@token}"}>
+  <.simple_form :let={f} for={@changeset} action={~p"<%= schema.route_prefix %>/reset-password/#{@token}"}>
     <.error :if={@changeset.action}>
       Oops, something went wrong! Please check the errors below.
     </.error>
@@ -24,6 +24,6 @@
 
   <p class="text-center text-sm mt-4">
     <.link href={~p"<%= schema.route_prefix %>/register"}>Register</.link>
-    | <.link href={~p"<%= schema.route_prefix %>/log_in"}>Log in</.link>
+    | <.link href={~p"<%= schema.route_prefix %>/log-in"}>Log in</.link>
   </p>
 </div>
diff --git a/priv/templates/phx.gen.auth/reset_password_live.ex b/priv/templates/phx.gen.auth/reset_password_live.ex
index 32845c9ee..8d07fd8a8 100644
--- a/priv/templates/phx.gen.auth/reset_password_live.ex
+++ b/priv/templates/phx.gen.auth/reset_password_live.ex
@@ -1,4 +1,4 @@
-defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>ResetPasswordLive do
+defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.ResetPassword do
   use <%= inspect context.web_module %>, :live_view
 
   alias <%= inspect context.module %>
@@ -32,7 +32,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
       <p class="text-center text-sm mt-4">
         <.link href={~p"<%= schema.route_prefix %>/register"}>Register</.link>
-        | <.link href={~p"<%= schema.route_prefix %>/log_in"}>Log in</.link>
+        | <.link href={~p"<%= schema.route_prefix %>/log-in"}>Log in</.link>
       </p>
     </div>
     """
@@ -61,7 +61,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
         {:noreply,
          socket
          |> put_flash(:info, "Password reset successfully.")
-         |> redirect(to: ~p"<%= schema.route_prefix %>/log_in")}
+         |> redirect(to: ~p"<%= schema.route_prefix %>/log-in")}
 
       {:error, changeset} ->
         {:noreply, assign_form(socket, Map.put(changeset, :action, :insert))}
diff --git a/priv/templates/phx.gen.auth/reset_password_new.html.heex b/priv/templates/phx.gen.auth/reset_password_new.html.heex
index 739078687..3d2e40b0d 100644
--- a/priv/templates/phx.gen.auth/reset_password_new.html.heex
+++ b/priv/templates/phx.gen.auth/reset_password_new.html.heex
@@ -4,7 +4,7 @@
     <:subtitle>We'll send a password reset link to your inbox</:subtitle>
   </.header>
 
-  <.simple_form :let={f} for={@conn.params["<%= schema.singular %>"]} as={:<%= schema.singular %>} action={~p"<%= schema.route_prefix %>/reset_password"}>
+  <.simple_form :let={f} for={@conn.params["<%= schema.singular %>"]} as={:<%= schema.singular %>} action={~p"<%= schema.route_prefix %>/reset-password"}>
     <.input field={f[:email]} type="email" placeholder="Email" required />
     <:actions>
       <.button phx-disable-with="Sending..." class="w-full">
@@ -15,6 +15,6 @@
 
   <p class="text-center text-sm mt-4">
     <.link href={~p"<%= schema.route_prefix %>/register"}>Register</.link>
-    | <.link href={~p"<%= schema.route_prefix %>/log_in"}>Log in</.link>
+    | <.link href={~p"<%= schema.route_prefix %>/log-in"}>Log in</.link>
   </p>
 </div>
diff --git a/priv/templates/phx.gen.auth/routes.ex b/priv/templates/phx.gen.auth/routes.ex
index 60ced3360..928ea70c4 100644
--- a/priv/templates/phx.gen.auth/routes.ex
+++ b/priv/templates/phx.gen.auth/routes.ex
@@ -6,22 +6,22 @@
 
     live_session :redirect_if_<%= schema.singular %>_is_authenticated,
       on_mount: [{<%= inspect auth_module %>, :redirect_if_<%= schema.singular %>_is_authenticated}] do
-      live "/<%= schema.plural %>/register", <%= inspect schema.alias %>RegistrationLive, :new
-      live "/<%= schema.plural %>/log_in", <%= inspect schema.alias %>LoginLive, :new
-      live "/<%= schema.plural %>/reset_password", <%= inspect schema.alias %>ForgotPasswordLive, :new
-      live "/<%= schema.plural %>/reset_password/:token", <%= inspect schema.alias %>ResetPasswordLive, :edit
+      live "/<%= schema.plural %>/register", <%= inspect schema.alias %>Live.Registration, :new
+      live "/<%= schema.plural %>/log-in", <%= inspect schema.alias %>Live.Login, :new
+      live "/<%= schema.plural %>/reset-password", <%= inspect schema.alias %>Live.ForgotPassword, :new
+      live "/<%= schema.plural %>/reset-password/:token", <%= inspect schema.alias %>Live.ResetPassword, :edit
     end
 
-    post "/<%= schema.plural %>/log_in", <%= inspect schema.alias %>SessionController, :create<% else %>
+    post "/<%= schema.plural %>/log-in", <%= inspect schema.alias %>SessionController, :create<% else %>
 
     get "/<%= schema.plural %>/register", <%= inspect schema.alias %>RegistrationController, :new
     post "/<%= schema.plural %>/register", <%= inspect schema.alias %>RegistrationController, :create
-    get "/<%= schema.plural %>/log_in", <%= inspect schema.alias %>SessionController, :new
-    post "/<%= schema.plural %>/log_in", <%= inspect schema.alias %>SessionController, :create
-    get "/<%= schema.plural %>/reset_password", <%= inspect schema.alias %>ResetPasswordController, :new
-    post "/<%= schema.plural %>/reset_password", <%= inspect schema.alias %>ResetPasswordController, :create
-    get "/<%= schema.plural %>/reset_password/:token", <%= inspect schema.alias %>ResetPasswordController, :edit
-    put "/<%= schema.plural %>/reset_password/:token", <%= inspect schema.alias %>ResetPasswordController, :update<% end %>
+    get "/<%= schema.plural %>/log-in", <%= inspect schema.alias %>SessionController, :new
+    post "/<%= schema.plural %>/log-in", <%= inspect schema.alias %>SessionController, :create
+    get "/<%= schema.plural %>/reset-password", <%= inspect schema.alias %>ResetPasswordController, :new
+    post "/<%= schema.plural %>/reset-password", <%= inspect schema.alias %>ResetPasswordController, :create
+    get "/<%= schema.plural %>/reset-password/:token", <%= inspect schema.alias %>ResetPasswordController, :edit
+    put "/<%= schema.plural %>/reset-password/:token", <%= inspect schema.alias %>ResetPasswordController, :update<% end %>
   end
 
   scope <%= router_scope %> do
@@ -29,24 +29,24 @@
 
     live_session :require_authenticated_<%= schema.singular %>,
       on_mount: [{<%= inspect auth_module %>, :ensure_authenticated}] do
-      live "/<%= schema.plural %>/settings", <%= inspect schema.alias %>SettingsLive, :edit
-      live "/<%= schema.plural %>/settings/confirm_email/:token", <%= inspect schema.alias %>SettingsLive, :confirm_email
+      live "/<%= schema.plural %>/settings", <%= inspect schema.alias %>Live.Settings, :edit
+      live "/<%= schema.plural %>/settings/confirm-email/:token", <%= inspect schema.alias %>Live.Settings, :confirm_email
     end<% else %>
 
     get "/<%= schema.plural %>/settings", <%= inspect schema.alias %>SettingsController, :edit
     put "/<%= schema.plural %>/settings", <%= inspect schema.alias %>SettingsController, :update
-    get "/<%= schema.plural %>/settings/confirm_email/:token", <%= inspect schema.alias %>SettingsController, :confirm_email<% end %>
+    get "/<%= schema.plural %>/settings/confirm-email/:token", <%= inspect schema.alias %>SettingsController, :confirm_email<% end %>
   end
 
   scope <%= router_scope %> do
     pipe_through [:browser]
 
-    delete "/<%= schema.plural %>/log_out", <%= inspect schema.alias %>SessionController, :delete<%= if live? do %>
+    delete "/<%= schema.plural %>/log-out", <%= inspect schema.alias %>SessionController, :delete<%= if live? do %>
 
     live_session :current_<%= schema.singular %>,
       on_mount: [{<%= inspect auth_module %>, :mount_current_<%= schema.singular %>}] do
-      live "/<%= schema.plural %>/confirm/:token", <%= inspect schema.alias %>ConfirmationLive, :edit
-      live "/<%= schema.plural %>/confirm", <%= inspect schema.alias %>ConfirmationInstructionsLive, :new
+      live "/<%= schema.plural %>/confirm/:token", <%= inspect schema.alias %>Live.Confirmation, :edit
+      live "/<%= schema.plural %>/confirm", <%= inspect schema.alias %>Live.ConfirmationInstructions, :new
     end<% else %>
     get "/<%= schema.plural %>/confirm", <%= inspect schema.alias %>ConfirmationController, :new
     post "/<%= schema.plural %>/confirm", <%= inspect schema.alias %>ConfirmationController, :create
diff --git a/priv/templates/phx.gen.auth/session_controller.ex b/priv/templates/phx.gen.auth/session_controller.ex
index cb76ac3ea..bab413a3c 100644
--- a/priv/templates/phx.gen.auth/session_controller.ex
+++ b/priv/templates/phx.gen.auth/session_controller.ex
@@ -8,7 +8,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     create(conn, params, "Account created successfully!")
   end
 
-  def create(conn, %{"_action" => "password_updated"} = params) do
+  def create(conn, %{"_action" => "password-updated"} = params) do
     conn
     |> put_session(:<%= schema.singular %>_return_to, ~p"<%= schema.route_prefix %>/settings")
     |> create(params, "Password updated successfully!")
@@ -30,7 +30,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       conn
       |> put_flash(:error, "Invalid email or password")
       |> put_flash(:email, String.slice(email, 0, 160))
-      |> redirect(to: ~p"<%= schema.route_prefix %>/log_in")
+      |> redirect(to: ~p"<%= schema.route_prefix %>/log-in")
     end
   end<% else %>
 
diff --git a/priv/templates/phx.gen.auth/session_new.html.heex b/priv/templates/phx.gen.auth/session_new.html.heex
index 341cf0b73..abddb592e 100644
--- a/priv/templates/phx.gen.auth/session_new.html.heex
+++ b/priv/templates/phx.gen.auth/session_new.html.heex
@@ -10,7 +10,7 @@
     </:subtitle>
   </.header>
 
-  <.simple_form :let={f} for={@conn.params["<%= schema.singular %>"]} as={:<%= schema.singular %>} action={~p"<%= schema.route_prefix %>/log_in"}>
+  <.simple_form :let={f} for={@conn.params["<%= schema.singular %>"]} as={:<%= schema.singular %>} action={~p"<%= schema.route_prefix %>/log-in"}>
     <.error :if={@error_message}><%%= @error_message %></.error>
 
     <.input field={f[:email]} type="email" label="Email" required />
@@ -18,7 +18,7 @@
 
     <:actions :let={f}>
       <.input field={f[:remember_me]} type="checkbox" label="Keep me logged in" />
-      <.link href={~p"<%= schema.route_prefix %>/reset_password"} class="text-sm font-semibold">
+      <.link href={~p"<%= schema.route_prefix %>/reset-password"} class="text-sm font-semibold">
         Forgot your password?
       </.link>
     </:actions>
diff --git a/priv/templates/phx.gen.auth/settings_controller.ex b/priv/templates/phx.gen.auth/settings_controller.ex
index 971c12df0..c046cf779 100644
--- a/priv/templates/phx.gen.auth/settings_controller.ex
+++ b/priv/templates/phx.gen.auth/settings_controller.ex
@@ -19,7 +19,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
         <%= inspect context.alias %>.deliver_<%= schema.singular %>_update_email_instructions(
           applied_<%= schema.singular %>,
           <%= schema.singular %>.email,
-          &url(~p"<%= schema.route_prefix %>/settings/confirm_email/#{&1}")
+          &url(~p"<%= schema.route_prefix %>/settings/confirm-email/#{&1}")
         )
 
         conn
diff --git a/priv/templates/phx.gen.auth/settings_live.ex b/priv/templates/phx.gen.auth/settings_live.ex
index b6958f43a..a1deeb080 100644
--- a/priv/templates/phx.gen.auth/settings_live.ex
+++ b/priv/templates/phx.gen.auth/settings_live.ex
@@ -1,4 +1,4 @@
-defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>SettingsLive do
+defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.Settings do
   use <%= inspect context.web_module %>, :live_view
 
   alias <%= inspect context.module %>
@@ -37,7 +37,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
         <.simple_form
           for={@password_form}
           id="password_form"
-          action={~p"<%= schema.route_prefix %>/log_in?_action=password_updated"}
+          action={~p"<%= schema.route_prefix %>/log-in?_action=password-updated"}
           method="post"
           phx-change="validate_password"
           phx-submit="update_password"
@@ -124,7 +124,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
         <%= inspect context.alias %>.deliver_<%= schema.singular %>_update_email_instructions(
           applied_<%= schema.singular %>,
           <%= schema.singular %>.email,
-          &url(~p"<%= schema.route_prefix %>/settings/confirm_email/#{&1}")
+          &url(~p"<%= schema.route_prefix %>/settings/confirm-email/#{&1}")
         )
 
         info = "A link to confirm your email change has been sent to the new address."
diff --git a/priv/templates/phx.gen.html/index.html.heex b/priv/templates/phx.gen.html/index.html.heex
index b6273d48a..772a71077 100644
--- a/priv/templates/phx.gen.html/index.html.heex
+++ b/priv/templates/phx.gen.html/index.html.heex
@@ -1,9 +1,11 @@
 <.header>
   Listing <%= schema.human_plural %>
   <:actions>
-    <.link href={~p"<%= schema.route_prefix %>/new"}>
-      <.button>New <%= schema.human_singular %></.button>
-    </.link>
+    <.button phx-click={JS.dispatch("click", to: {:inner, "a"})}> 
+      <.link href={~p"<%= schema.route_prefix %>/new"}>
+        New <%= schema.human_singular %>
+      </.link>
+    </.button>
   </:actions>
 </.header>
 
diff --git a/priv/templates/phx.gen.html/show.html.heex b/priv/templates/phx.gen.html/show.html.heex
index 344289278..9b46db567 100644
--- a/priv/templates/phx.gen.html/show.html.heex
+++ b/priv/templates/phx.gen.html/show.html.heex
@@ -2,9 +2,11 @@
   <%= schema.human_singular %> <%%= @<%= schema.singular %>.id %>
   <:subtitle>This is a <%= schema.singular %> record from your database.</:subtitle>
   <:actions>
-    <.link href={~p"<%= schema.route_prefix %>/#{@<%= schema.singular %>}/edit"}>
-      <.button>Edit <%= schema.singular %></.button>
-    </.link>
+    <.button phx-click={JS.dispatch("click", to: {:inner, "a"})}>
+      <.link href={~p"<%= schema.route_prefix %>/#{@<%= schema.singular %>}/edit"}>
+        Edit <%= schema.singular %>
+      </.link>
+    </.button>
   </:actions>
 </.header>
 
diff --git a/priv/templates/phx.gen.live/core_components.ex b/priv/templates/phx.gen.live/core_components.ex
index 1aa9858b7..c604ef553 100644
--- a/priv/templates/phx.gen.live/core_components.ex
+++ b/priv/templates/phx.gen.live/core_components.ex
@@ -76,7 +76,7 @@ defmodule <%= @web_namespace %>.CoreComponents do
 
   def flash_group(assigns) do
     ~H"""
-    <div id={@id}>
+    <div id={@id} aria-live="polite">
       <.flash kind={:info} title=<%= maybe_heex_attr_gettext.("Success!", @gettext) %> flash={@flash} />
       <.flash kind={:error} title=<%= maybe_heex_attr_gettext.("Error!", @gettext) %> flash={@flash} />
       <.flash
@@ -120,7 +120,7 @@ defmodule <%= @web_namespace %>.CoreComponents do
       </.simple_form>
   """
   attr :for, :any, required: true, doc: "the data structure for the form"
-  attr :as, :any, default: nil, doc: "the server side parameter to collect all input under"
+  attr :as, :any, doc: "the server side parameter to collect all input under"
 
   attr :rest, :global,
     include: ~w(autocomplete name rel action enctype method novalidate target multipart),
@@ -130,8 +130,10 @@ defmodule <%= @web_namespace %>.CoreComponents do
   slot :actions, doc: "the slot for form actions, such as a submit button"
 
   def simple_form(assigns) do
+    assigns = assign(assigns, :as, if(assigns[:as], do: %{as: assigns[:as]}, else: %{}))
+
     ~H"""
-    <.form :let={f} for={@for} as={@as} {@rest}>
+    <.form :let={f} for={@for} {@as} {@rest}>
       <div class="mt-10 space-y-8 bg-white">
         <%%= render_slot(@inner_block, f) %>
         <div :for={action <- @actions} class="mt-2 flex items-center justify-between gap-6">
diff --git a/priv/templates/phx.gen.live/index.ex b/priv/templates/phx.gen.live/index.ex
index d6055a669..ff23665ab 100644
--- a/priv/templates/phx.gen.live/index.ex
+++ b/priv/templates/phx.gen.live/index.ex
@@ -9,9 +9,11 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     <.header>
       Listing <%= schema.human_plural %>
       <:actions>
-        <.link navigate={~p"<%= schema.route_prefix %>/new"}>
-          <.button>New <%= schema.human_singular %></.button>
-        </.link>
+        <.button phx-click={JS.dispatch("click", to: {:inner, "a"})}>
+          <.link navigate={~p"<%= schema.route_prefix %>/new"}>
+            New <%= schema.human_singular %>
+          </.link>
+        </.button>
       </:actions>
     </.header>
 
diff --git a/priv/templates/phx.gen.live/show.ex b/priv/templates/phx.gen.live/show.ex
index 6d6e1ac27..140016c74 100644
--- a/priv/templates/phx.gen.live/show.ex
+++ b/priv/templates/phx.gen.live/show.ex
@@ -10,9 +10,11 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       <%= schema.human_singular %> <%%= @<%= schema.singular %>.id %>
       <:subtitle>This is a <%= schema.singular %> record from your database.</:subtitle>
       <:actions>
-        <.link navigate={~p"<%= schema.route_prefix %>/#{@<%= schema.singular %>}/edit?return_to=show"}>
-          <.button>Edit <%= schema.singular %></.button>
-        </.link>
+        <.button phx-click={JS.dispatch("click", to: {:inner, "a"})}>
+          <.link navigate={~p"<%= schema.route_prefix %>/#{@<%= schema.singular %>}/edit?return_to=show"}>
+            Edit <%= schema.singular %>
+          </.link>
+        </.button>
       </:actions>
     </.header>
 


Test patch:
diff --git a/installer/templates/phx_test/controllers/error_html_test.exs b/installer/templates/phx_test/controllers/error_html_test.exs
index 6d3396470..74098fc30 100644
--- a/installer/templates/phx_test/controllers/error_html_test.exs
+++ b/installer/templates/phx_test/controllers/error_html_test.exs
@@ -2,7 +2,7 @@ defmodule <%= @web_namespace %>.ErrorHTMLTest do
   use <%= @web_namespace %>.ConnCase, async: true
 
   # Bring render_to_string/4 for testing custom views
-  import Phoenix.Template
+  import Phoenix.Template, only: [render_to_string: 4]
 
   test "renders 404.html" do
     assert render_to_string(<%= @web_namespace %>.ErrorHTML, "404", "html", []) == "Not Found"
diff --git a/integration_test/mix.exs b/integration_test/mix.exs
index 731c09dde..63cedf531 100644
--- a/integration_test/mix.exs
+++ b/integration_test/mix.exs
@@ -42,7 +42,7 @@ defmodule Phoenix.Integration.MixProject do
       {:ecto_sqlite3, ">= 0.0.0"},
       {:phoenix_html, "~> 4.1"},
       # TODO bump on release to {:phoenix_live_view, "~> 1.0.0"},
-      {:phoenix_live_view, "~> 1.0.0-rc.1", override: true},
+      {:phoenix_live_view, "~> 1.0.0-rc.0", override: true},
       {:dns_cluster, "~> 0.1.1"},
       {:floki, ">= 0.30.0"},
       {:phoenix_live_reload, "~> 1.2"},
diff --git a/integration_test/mix.lock b/integration_test/mix.lock
index 59d00655d..6ce1c9a9c 100644
--- a/integration_test/mix.lock
+++ b/integration_test/mix.lock
@@ -6,7 +6,7 @@
   "cc_precompiler": {:hex, :cc_precompiler, "0.1.10", "47c9c08d8869cf09b41da36538f62bc1abd3e19e41701c2cea2675b53c704258", [:mix], [{:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "f6e046254e53cd6b41c6bacd70ae728011aa82b2742a80d6e2214855c6e06b22"},
   "comeonin": {:hex, :comeonin, "5.5.0", "364d00df52545c44a139bad919d7eacb55abf39e86565878e17cebb787977368", [:mix], [], "hexpm", "6287fc3ba0aad34883cbe3f7949fc1d1e738e5ccdce77165bc99490aa69f47fb"},
   "db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"},
-  "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
+  "decimal": {:hex, :decimal, "2.2.0", "df3d06bb9517e302b1bd265c1e7f16cda51547ad9d99892049340841f3e15836", [:mix], [], "hexpm", "af8daf87384b51b7e611fb1a1f2c4d4876b65ef968fa8bd3adf44cff401c7f21"},
   "dns_cluster": {:hex, :dns_cluster, "0.1.3", "0bc20a2c88ed6cc494f2964075c359f8c2d00e1bf25518a6a6c7fd277c9b0c66", [:mix], [], "hexpm", "46cb7c4a1b3e52c7ad4cbe33ca5079fbde4840dedeafca2baf77996c2da1bc33"},
   "ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"},
   "ecto_sql": {:hex, :ecto_sql, "3.11.3", "4eb7348ff8101fbc4e6bbc5a4404a24fecbe73a3372d16569526b0cf34ebc195", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e5f36e3d736b99c7fee3e631333b8394ade4bafe9d96d35669fca2d81c2be928"},
@@ -17,11 +17,11 @@
   "exqlite": {:hex, :exqlite, "0.23.0", "6e851c937a033299d0784994c66da24845415072adbc455a337e20087bce9033", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.8", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "404341cceec5e6466aaed160cf0b58be2019b60af82588c215e1224ebd3ec831"},
   "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"},
   "finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"},
-  "floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"},
+  "floki": {:hex, :floki, "0.36.3", "1102f93b16a55bc5383b85ae3ec470f82dee056eaeff9195e8afdf0ef2a43c30", [:mix], [], "hexpm", "fe0158bff509e407735f6d40b3ee0d7deb47f3f3ee7c6c182ad28599f9f6b27a"},
   "gettext": {:hex, :gettext, "0.26.1", "38e14ea5dcf962d1fc9f361b63ea07c0ce715a8ef1f9e82d3dfb8e67e0416715", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "01ce56f188b9dc28780a52783d6529ad2bc7124f9744e571e1ee4ea88bf08734"},
   "heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized", depth: 1]},
   "hpax": {:hex, :hpax, "0.2.0", "5a58219adcb75977b2edce5eb22051de9362f08236220c9e859a47111c194ff5", [:mix], [], "hexpm", "bea06558cdae85bed075e6c036993d43cd54d447f76d8190a8db0dc5893fa2f1"},
-  "jason": {:hex, :jason, "1.4.3", "d3f984eeb96fe53b85d20e0b049f03e57d075b5acda3ac8d465c969a2536c17b", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "9a90e868927f7c777689baa16d86f4d0e086d968db5c05d917ccff6d443e58a3"},
+  "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
   "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"},
   "mint": {:hex, :mint, "1.6.2", "af6d97a4051eee4f05b5500671d47c3a67dac7386045d87a904126fd4bbcea2e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5ee441dffc1892f1ae59127f74afe8fd82fda6587794278d924e4d90ea3d63f9"},
   "myxql": {:hex, :myxql, "0.7.0", "3382f139b0b0da977a8fc33c8cded125e20df2e400f8d7b7e674fa62a7e077dd", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:geo, "~> 3.4", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "40e4b7ad4973c8b895e86a3de04ff7a79c2cf72b9f2bddef7717afb4ab36d8c0"},
@@ -32,7 +32,7 @@
   "phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"},
   "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.3", "7ff51c9b6609470f681fbea20578dede0e548302b0c8bdf338b5a753a4f045bf", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "f9470a0a8bae4f56430a23d42f977b5a6205fdba6559d76f932b876bfaec652d"},
   "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.5.3", "f2161c207fda0e4fb55165f650f7f8db23f02b29e3bff00ff7ef161d6ac1f09d", [:mix], [{:file_system, "~> 0.3 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "b4ec9cd73cb01ff1bd1cac92e045d13e7030330b74164297d1aee3907b54803c"},
-  "phoenix_live_view": {:hex, :phoenix_live_view, "1.0.0-rc.1", "adfb0ab3edbad3bac63661ee0367c803d96178b8e8bbb8ff2b6c7cebdb820491", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ffc940d7af43c3d6c26faa7693872f95178f4ca886434224d29d4b54d3a38ae3"},
+  "phoenix_live_view": {:hex, :phoenix_live_view, "1.0.0-rc.7", "d2abca526422adea88896769529addb6443390b1d4f1ff9cbe694312d8875fb2", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b82a4575f6f3eb5b97922ec6874b0c52b3ca0cc5dcb4b14ddc478cbfa135dd01"},
   "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
   "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
   "plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"},
@@ -42,7 +42,7 @@
   "swoosh": {:hex, :swoosh, "1.16.9", "20c6a32ea49136a4c19f538e27739bb5070558c0fa76b8a95f4d5d5ca7d319a1", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.0", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "878b1a7a6c10ebbf725a3349363f48f79c5e3d792eb621643b0d276a38acc0a6"},
   "tailwind": {:hex, :tailwind, "0.2.3", "277f08145d407de49650d0a4685dc062174bdd1ae7731c5f1da86163a24dfcdb", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "8e45e7a34a676a7747d04f7913a96c770c85e6be810a1d7f91e713d3a3655b5d"},
   "tds": {:hex, :tds, "2.3.5", "fedfb96d53206f01eac62ead859e47e1541a62e1553e9eb7a8801c7dca59eae8", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "52e350f5dd5584bbcff9859e331be144d290b41bd4c749b936014a17660662f2"},
-  "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
+  "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
   "telemetry_metrics": {:hex, :telemetry_metrics, "1.0.0", "29f5f84991ca98b8eb02fc208b2e6de7c95f8bb2294ef244a176675adc7775df", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f23713b3847286a534e005126d4c959ebcca68ae9582118ce436b521d1d47d5d"},
   "telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"},
   "thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"},
diff --git a/priv/templates/phx.gen.auth/auth_test.exs b/priv/templates/phx.gen.auth/auth_test.exs
index bafdfd6b7..cb7943b5e 100644
--- a/priv/templates/phx.gen.auth/auth_test.exs
+++ b/priv/templates/phx.gen.auth/auth_test.exs
@@ -231,7 +231,7 @@ defmodule <%= inspect auth_module %>Test do
       conn = conn |> fetch_flash() |> <%= inspect schema.alias %>Auth.require_authenticated_<%= schema.singular %>([])
       assert conn.halted
 
-      assert redirected_to(conn) == ~p"<%= schema.route_prefix %>/log_in"
+      assert redirected_to(conn) == ~p"<%= schema.route_prefix %>/log-in"
 
       assert Phoenix.Flash.get(conn.assigns.flash, :error) ==
                "You must log in to access this page."
diff --git a/priv/templates/phx.gen.auth/confirmation_instructions_live_test.exs b/priv/templates/phx.gen.auth/confirmation_instructions_live_test.exs
index c1ac8b654..d8d1d2376 100644
--- a/priv/templates/phx.gen.auth/confirmation_instructions_live_test.exs
+++ b/priv/templates/phx.gen.auth/confirmation_instructions_live_test.exs
@@ -1,4 +1,4 @@
-defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>ConfirmationInstructionsLiveTest do
+defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.ConfirmationInstructionsTest do
   use <%= inspect context.web_module %>.ConnCase<%= test_case_options %>
 
   import Phoenix.LiveViewTest
diff --git a/priv/templates/phx.gen.auth/confirmation_live_test.exs b/priv/templates/phx.gen.auth/confirmation_live_test.exs
index fc3112882..0eac2e43c 100644
--- a/priv/templates/phx.gen.auth/confirmation_live_test.exs
+++ b/priv/templates/phx.gen.auth/confirmation_live_test.exs
@@ -1,4 +1,4 @@
-defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>ConfirmationLiveTest do
+defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.ConfirmationTest do
   use <%= inspect context.web_module %>.ConnCase<%= test_case_options %>
 
   import Phoenix.LiveViewTest
diff --git a/priv/templates/phx.gen.auth/forgot_password_live_test.exs b/priv/templates/phx.gen.auth/forgot_password_live_test.exs
index 4ad1455f6..2a7f5b362 100644
--- a/priv/templates/phx.gen.auth/forgot_password_live_test.exs
+++ b/priv/templates/phx.gen.auth/forgot_password_live_test.exs
@@ -1,4 +1,4 @@
-defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>ForgotPasswordLiveTest do
+defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.ForgotPasswordTest do
   use <%= inspect context.web_module %>.ConnCase<%= test_case_options %>
 
   import Phoenix.LiveViewTest
@@ -9,18 +9,18 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
   describe "Forgot password page" do
     test "renders email page", %{conn: conn} do
-      {:ok, lv, html} = live(conn, ~p"<%= schema.route_prefix %>/reset_password")
+      {:ok, lv, html} = live(conn, ~p"<%= schema.route_prefix %>/reset-password")
 
       assert html =~ "Forgot your password?"
       assert has_element?(lv, ~s|a[href="#{~p"<%= schema.route_prefix %>/register"}"]|, "Register")
-      assert has_element?(lv, ~s|a[href="#{~p"<%= schema.route_prefix %>/log_in"}"]|, "Log in")
+      assert has_element?(lv, ~s|a[href="#{~p"<%= schema.route_prefix %>/log-in"}"]|, "Log in")
     end
 
     test "redirects if already logged in", %{conn: conn} do
       result =
         conn
         |> log_in_<%= schema.singular %>(<%= schema.singular %>_fixture())
-        |> live(~p"<%= schema.route_prefix %>/reset_password")
+        |> live(~p"<%= schema.route_prefix %>/reset-password")
         |> follow_redirect(conn, ~p"/")
 
       assert {:ok, _conn} = result
@@ -33,7 +33,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     end
 
     test "sends a new reset password token", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>} do
-      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/reset_password")
+      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/reset-password")
 
       {:ok, conn} =
         lv
@@ -48,7 +48,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     end
 
     test "does not send reset password token if email is invalid", %{conn: conn} do
-      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/reset_password")
+      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/reset-password")
 
       {:ok, conn} =
         lv
diff --git a/priv/templates/phx.gen.auth/login_live_test.exs b/priv/templates/phx.gen.auth/login_live_test.exs
index 6b9d14268..11516b78a 100644
--- a/priv/templates/phx.gen.auth/login_live_test.exs
+++ b/priv/templates/phx.gen.auth/login_live_test.exs
@@ -1,4 +1,4 @@
-defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>LoginLiveTest do
+defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.LoginTest do
   use <%= inspect context.web_module %>.ConnCase<%= test_case_options %>
 
   import Phoenix.LiveViewTest
@@ -6,7 +6,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
   describe "Log in page" do
     test "renders log in page", %{conn: conn} do
-      {:ok, _lv, html} = live(conn, ~p"<%= schema.route_prefix %>/log_in")
+      {:ok, _lv, html} = live(conn, ~p"<%= schema.route_prefix %>/log-in")
 
       assert html =~ "Log in"
       assert html =~ "Register"
@@ -17,7 +17,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       result =
         conn
         |> log_in_<%= schema.singular %>(<%= schema.singular %>_fixture())
-        |> live(~p"<%= schema.route_prefix %>/log_in")
+        |> live(~p"<%= schema.route_prefix %>/log-in")
         |> follow_redirect(conn, ~p"/")
 
       assert {:ok, _conn} = result
@@ -29,7 +29,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       password = "123456789abcd"
       <%= schema.singular %> = <%= schema.singular %>_fixture(%{password: password})
 
-      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/log_in")
+      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/log-in")
 
       form =
         form(lv, "#login_form", <%= schema.singular %>: %{email: <%= schema.singular %>.email, password: password, remember_me: true})
@@ -42,7 +42,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     test "redirects to login page with a flash error if there are no valid credentials", %{
       conn: conn
     } do
-      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/log_in")
+      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/log-in")
 
       form =
         form(lv, "#login_form",
@@ -53,13 +53,13 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
       assert Phoenix.Flash.get(conn.assigns.flash, :error) == "Invalid email or password"
 
-      assert redirected_to(conn) == "<%= schema.route_prefix %>/log_in"
+      assert redirected_to(conn) == "<%= schema.route_prefix %>/log-in"
     end
   end
 
   describe "login navigation" do
     test "redirects to registration page when the Register button is clicked", %{conn: conn} do
-      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/log_in")
+      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/log-in")
 
       {:ok, _login_live, login_html} =
         lv
@@ -73,13 +73,13 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     test "redirects to forgot password page when the Forgot Password button is clicked", %{
       conn: conn
     } do
-      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/log_in")
+      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/log-in")
 
       {:ok, conn} =
         lv
         |> element(~s|main a:fl-contains("Forgot your password?")|)
         |> render_click()
-        |> follow_redirect(conn, ~p"<%= schema.route_prefix %>/reset_password")
+        |> follow_redirect(conn, ~p"<%= schema.route_prefix %>/reset-password")
 
       assert conn.resp_body =~ "Forgot your password?"
     end
diff --git a/priv/templates/phx.gen.auth/registration_controller_test.exs b/priv/templates/phx.gen.auth/registration_controller_test.exs
index 2682277b0..53dfbb2e6 100644
--- a/priv/templates/phx.gen.auth/registration_controller_test.exs
+++ b/priv/templates/phx.gen.auth/registration_controller_test.exs
@@ -8,7 +8,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       conn = get(conn, ~p"<%= schema.route_prefix %>/register")
       response = html_response(conn, 200)
       assert response =~ "Register"
-      assert response =~ ~p"<%= schema.route_prefix %>/log_in"
+      assert response =~ ~p"<%= schema.route_prefix %>/log-in"
       assert response =~ ~p"<%= schema.route_prefix %>/register"
     end
 
@@ -37,7 +37,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       response = html_response(conn, 200)
       assert response =~ email
       assert response =~ ~p"<%= schema.route_prefix %>/settings"
-      assert response =~ ~p"<%= schema.route_prefix %>/log_out"
+      assert response =~ ~p"<%= schema.route_prefix %>/log-out"
     end
 
     test "render errors for invalid data", %{conn: conn} do
diff --git a/priv/templates/phx.gen.auth/registration_live_test.exs b/priv/templates/phx.gen.auth/registration_live_test.exs
index 1d1246819..8c878d301 100644
--- a/priv/templates/phx.gen.auth/registration_live_test.exs
+++ b/priv/templates/phx.gen.auth/registration_live_test.exs
@@ -1,4 +1,4 @@
-defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>RegistrationLiveTest do
+defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.RegistrationTest do
   use <%= inspect context.web_module %>.ConnCase<%= test_case_options %>
 
   import Phoenix.LiveViewTest
@@ -79,7 +79,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
         lv
         |> element(~s|main a:fl-contains("Log in")|)
         |> render_click()
-        |> follow_redirect(conn, ~p"<%= schema.route_prefix %>/log_in")
+        |> follow_redirect(conn, ~p"<%= schema.route_prefix %>/log-in")
 
       assert login_html =~ "Log in"
     end
diff --git a/priv/templates/phx.gen.auth/reset_password_controller_test.exs b/priv/templates/phx.gen.auth/reset_password_controller_test.exs
index f622b51e0..dcf0dc5c9 100644
--- a/priv/templates/phx.gen.auth/reset_password_controller_test.exs
+++ b/priv/templates/phx.gen.auth/reset_password_controller_test.exs
@@ -9,19 +9,19 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     %{<%= schema.singular %>: <%= schema.singular %>_fixture()}
   end
 
-  describe "GET <%= schema.route_prefix %>/reset_password" do
+  describe "GET <%= schema.route_prefix %>/reset-password" do
     test "renders the reset password page", %{conn: conn} do
-      conn = get(conn, ~p"<%= schema.route_prefix %>/reset_password")
+      conn = get(conn, ~p"<%= schema.route_prefix %>/reset-password")
       response = html_response(conn, 200)
       assert response =~ "Forgot your password?"
     end
   end
 
-  describe "POST <%= schema.route_prefix %>/reset_password" do
+  describe "POST <%= schema.route_prefix %>/reset-password" do
     @tag :capture_log
     test "sends a new reset password token", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>} do
       conn =
-        post(conn, ~p"<%= schema.route_prefix %>/reset_password", %{
+        post(conn, ~p"<%= schema.route_prefix %>/reset-password", %{
           "<%= schema.singular %>" => %{"email" => <%= schema.singular %>.email}
         })
 
@@ -35,7 +35,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
     test "does not send reset password token if email is invalid", %{conn: conn} do
       conn =
-        post(conn, ~p"<%= schema.route_prefix %>/reset_password", %{
+        post(conn, ~p"<%= schema.route_prefix %>/reset-password", %{
           "<%= schema.singular %>" => %{"email" => "unknown@example.com"}
         })
 
@@ -48,7 +48,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     end
   end
 
-  describe "GET <%= schema.route_prefix %>/reset_password/:token" do
+  describe "GET <%= schema.route_prefix %>/reset-password/:token" do
     setup %{<%= schema.singular %>: <%= schema.singular %>} do
       token =
         extract_<%= schema.singular %>_token(fn url ->
@@ -59,12 +59,12 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     end
 
     test "renders reset password", %{conn: conn, token: token} do
-      conn = get(conn, ~p"<%= schema.route_prefix %>/reset_password/#{token}")
+      conn = get(conn, ~p"<%= schema.route_prefix %>/reset-password/#{token}")
       assert html_response(conn, 200) =~ "Reset password"
     end
 
     test "does not render reset password with invalid token", %{conn: conn} do
-      conn = get(conn, ~p"<%= schema.route_prefix %>/reset_password/oops")
+      conn = get(conn, ~p"<%= schema.route_prefix %>/reset-password/oops")
       assert redirected_to(conn) == ~p"/"
 
       assert Phoenix.Flash.get(conn.assigns.flash, :error) =~
@@ -72,7 +72,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     end
   end
 
-  describe "PUT <%= schema.route_prefix %>/reset_password/:token" do
+  describe "PUT <%= schema.route_prefix %>/reset-password/:token" do
     setup %{<%= schema.singular %>: <%= schema.singular %>} do
       token =
         extract_<%= schema.singular %>_token(fn url ->
@@ -84,14 +84,14 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
     test "resets password once", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>, token: token} do
       conn =
-        put(conn, ~p"<%= schema.route_prefix %>/reset_password/#{token}", %{
+        put(conn, ~p"<%= schema.route_prefix %>/reset-password/#{token}", %{
           "<%= schema.singular %>" => %{
             "password" => "new valid password",
             "password_confirmation" => "new valid password"
           }
         })
 
-      assert redirected_to(conn) == ~p"<%= schema.route_prefix %>/log_in"
+      assert redirected_to(conn) == ~p"<%= schema.route_prefix %>/log-in"
       refute get_session(conn, :<%= schema.singular %>_token)
 
       assert Phoenix.Flash.get(conn.assigns.flash, :info) =~
@@ -102,7 +102,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
     test "does not reset password on invalid data", %{conn: conn, token: token} do
       conn =
-        put(conn, ~p"<%= schema.route_prefix %>/reset_password/#{token}", %{
+        put(conn, ~p"<%= schema.route_prefix %>/reset-password/#{token}", %{
           "<%= schema.singular %>" => %{
             "password" => "too short",
             "password_confirmation" => "does not match"
@@ -113,7 +113,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     end
 
     test "does not reset password with invalid token", %{conn: conn} do
-      conn = put(conn, ~p"<%= schema.route_prefix %>/reset_password/oops")
+      conn = put(conn, ~p"<%= schema.route_prefix %>/reset-password/oops")
       assert redirected_to(conn) == ~p"/"
 
       assert Phoenix.Flash.get(conn.assigns.flash, :error) =~
diff --git a/priv/templates/phx.gen.auth/reset_password_live_test.exs b/priv/templates/phx.gen.auth/reset_password_live_test.exs
index 4e4995dd3..6e73bfe8e 100644
--- a/priv/templates/phx.gen.auth/reset_password_live_test.exs
+++ b/priv/templates/phx.gen.auth/reset_password_live_test.exs
@@ -1,4 +1,4 @@
-defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>ResetPasswordLiveTest do
+defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.ResetPasswordTest do
   use <%= inspect context.web_module %>.ConnCase<%= test_case_options %>
 
   import Phoenix.LiveViewTest
@@ -19,13 +19,13 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
   describe "Reset password page" do
     test "renders reset password with valid token", %{conn: conn, token: token} do
-      {:ok, _lv, html} = live(conn, ~p"<%= schema.route_prefix %>/reset_password/#{token}")
+      {:ok, _lv, html} = live(conn, ~p"<%= schema.route_prefix %>/reset-password/#{token}")
 
       assert html =~ "Reset Password"
     end
 
     test "does not render reset password with invalid token", %{conn: conn} do
-      {:error, {:redirect, to}} = live(conn, ~p"<%= schema.route_prefix %>/reset_password/invalid")
+      {:error, {:redirect, to}} = live(conn, ~p"<%= schema.route_prefix %>/reset-password/invalid")
 
       assert to == %{
                flash: %{"error" => "Reset password link is invalid or it has expired."},
@@ -34,7 +34,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     end
 
     test "renders errors for invalid data", %{conn: conn, token: token} do
-      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/reset_password/#{token}")
+      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/reset-password/#{token}")
 
       result =
         lv
@@ -50,7 +50,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
   describe "Reset Password" do
     test "resets password once", %{conn: conn, token: token, <%= schema.singular %>: <%= schema.singular %>} do
-      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/reset_password/#{token}")
+      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/reset-password/#{token}")
 
       {:ok, conn} =
         lv
@@ -61,7 +61,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
           }
         )
         |> render_submit()
-        |> follow_redirect(conn, ~p"<%= schema.route_prefix %>/log_in")
+        |> follow_redirect(conn, ~p"<%= schema.route_prefix %>/log-in")
 
       refute get_session(conn, :<%= schema.singular %>_token)
       assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Password reset successfully"
@@ -69,7 +69,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     end
 
     test "does not reset password on invalid data", %{conn: conn, token: token} do
-      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/reset_password/#{token}")
+      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/reset-password/#{token}")
 
       result =
         lv
@@ -89,13 +89,13 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
   describe "Reset password navigation" do
     test "redirects to login page when the Log in button is clicked", %{conn: conn, token: token} do
-      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/reset_password/#{token}")
+      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/reset-password/#{token}")
 
       {:ok, conn} =
         lv
         |> element(~s|main a:fl-contains("Log in")|)
         |> render_click()
-        |> follow_redirect(conn, ~p"<%= schema.route_prefix %>/log_in")
+        |> follow_redirect(conn, ~p"<%= schema.route_prefix %>/log-in")
 
       assert conn.resp_body =~ "Log in"
     end
@@ -104,7 +104,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       conn: conn,
       token: token
     } do
-      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/reset_password/#{token}")
+      {:ok, lv, _html} = live(conn, ~p"<%= schema.route_prefix %>/reset-password/#{token}")
 
       {:ok, conn} =
         lv
diff --git a/priv/templates/phx.gen.auth/session_controller_test.exs b/priv/templates/phx.gen.auth/session_controller_test.exs
index 70473c2ce..8004208b1 100644
--- a/priv/templates/phx.gen.auth/session_controller_test.exs
+++ b/priv/templates/phx.gen.auth/session_controller_test.exs
@@ -7,9 +7,9 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     %{<%= schema.singular %>: <%= schema.singular %>_fixture()}
   end<%= if not live? do %>
 
-  describe "GET <%= schema.route_prefix %>/log_in" do
+  describe "GET <%= schema.route_prefix %>/log-in" do
     test "renders log in page", %{conn: conn} do
-      conn = get(conn, ~p"<%= schema.route_prefix %>/log_in")
+      conn = get(conn, ~p"<%= schema.route_prefix %>/log-in")
       response = html_response(conn, 200)
       assert response =~ "Log in"
       assert response =~ ~p"<%= schema.route_prefix %>/register"
@@ -17,15 +17,15 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     end
 
     test "redirects if already logged in", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>} do
-      conn = conn |> log_in_<%= schema.singular %>(<%= schema.singular %>) |> get(~p"<%= schema.route_prefix %>/log_in")
+      conn = conn |> log_in_<%= schema.singular %>(<%= schema.singular %>) |> get(~p"<%= schema.route_prefix %>/log-in")
       assert redirected_to(conn) == ~p"/"
     end
   end<% end %>
 
-  describe "POST <%= schema.route_prefix %>/log_in" do
+  describe "POST <%= schema.route_prefix %>/log-in" do
     test "logs the <%= schema.singular %> in", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>} do
       conn =
-        post(conn, ~p"<%= schema.route_prefix %>/log_in", %{
+        post(conn, ~p"<%= schema.route_prefix %>/log-in", %{
           "<%= schema.singular %>" => %{"email" => <%= schema.singular %>.email, "password" => valid_<%= schema.singular %>_password()}
         })
 
@@ -37,12 +37,12 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       response = html_response(conn, 200)
       assert response =~ <%= schema.singular %>.email
       assert response =~ ~p"<%= schema.route_prefix %>/settings"
-      assert response =~ ~p"<%= schema.route_prefix %>/log_out"
+      assert response =~ ~p"<%= schema.route_prefix %>/log-out"
     end
 
     test "logs the <%= schema.singular %> in with remember me", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>} do
       conn =
-        post(conn, ~p"<%= schema.route_prefix %>/log_in", %{
+        post(conn, ~p"<%= schema.route_prefix %>/log-in", %{
           "<%= schema.singular %>" => %{
             "email" => <%= schema.singular %>.email,
             "password" => valid_<%= schema.singular %>_password(),
@@ -58,7 +58,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       conn =
         conn
         |> init_test_session(<%= schema.singular %>_return_to: "/foo/bar")
-        |> post(~p"<%= schema.route_prefix %>/log_in", %{
+        |> post(~p"<%= schema.route_prefix %>/log-in", %{
           "<%= schema.singular %>" => %{
             "email" => <%= schema.singular %>.email,
             "password" => valid_<%= schema.singular %>_password()
@@ -72,7 +72,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     test "login following registration", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>} do
       conn =
         conn
-        |> post(~p"<%= schema.route_prefix %>/log_in", %{
+        |> post(~p"<%= schema.route_prefix %>/log-in", %{
           "_action" => "registered",
           "<%= schema.singular %>" => %{
             "email" => <%= schema.singular %>.email,
@@ -87,8 +87,8 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     test "login following password update", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>} do
       conn =
         conn
-        |> post(~p"<%= schema.route_prefix %>/log_in", %{
-          "_action" => "password_updated",
+        |> post(~p"<%= schema.route_prefix %>/log-in", %{
+          "_action" => "password-updated",
           "<%= schema.singular %>" => %{
             "email" => <%= schema.singular %>.email,
             "password" => valid_<%= schema.singular %>_password()
@@ -101,17 +101,17 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
     test "redirects to login page with invalid credentials", %{conn: conn} do
       conn =
-        post(conn, ~p"<%= schema.route_prefix %>/log_in", %{
+        post(conn, ~p"<%= schema.route_prefix %>/log-in", %{
           "<%= schema.singular %>" => %{"email" => "invalid@email.com", "password" => "invalid_password"}
         })
 
       assert Phoenix.Flash.get(conn.assigns.flash, :error) == "Invalid email or password"
-      assert redirected_to(conn) == ~p"<%= schema.route_prefix %>/log_in"
+      assert redirected_to(conn) == ~p"<%= schema.route_prefix %>/log-in"
     end<% else %>
 
     test "emits error message with invalid credentials", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>} do
       conn =
-        post(conn, ~p"<%= schema.route_prefix %>/log_in", %{
+        post(conn, ~p"<%= schema.route_prefix %>/log-in", %{
           "<%= schema.singular %>" => %{"email" => <%= schema.singular %>.email, "password" => "invalid_password"}
         })
 
@@ -121,16 +121,16 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     end<% end %>
   end
 
-  describe "DELETE <%= schema.route_prefix %>/log_out" do
+  describe "DELETE <%= schema.route_prefix %>/log-out" do
     test "logs the <%= schema.singular %> out", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>} do
-      conn = conn |> log_in_<%= schema.singular %>(<%= schema.singular %>) |> delete(~p"<%= schema.route_prefix %>/log_out")
+      conn = conn |> log_in_<%= schema.singular %>(<%= schema.singular %>) |> delete(~p"<%= schema.route_prefix %>/log-out")
       assert redirected_to(conn) == ~p"/"
       refute get_session(conn, :<%= schema.singular %>_token)
       assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Logged out successfully"
     end
 
     test "succeeds even if the <%= schema.singular %> is not logged in", %{conn: conn} do
-      conn = delete(conn, ~p"<%= schema.route_prefix %>/log_out")
+      conn = delete(conn, ~p"<%= schema.route_prefix %>/log-out")
       assert redirected_to(conn) == ~p"/"
       refute get_session(conn, :<%= schema.singular %>_token)
       assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Logged out successfully"
diff --git a/priv/templates/phx.gen.auth/settings_controller_test.exs b/priv/templates/phx.gen.auth/settings_controller_test.exs
index 7c83ed554..6f5ce220d 100644
--- a/priv/templates/phx.gen.auth/settings_controller_test.exs
+++ b/priv/templates/phx.gen.auth/settings_controller_test.exs
@@ -16,7 +16,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     test "redirects if <%= schema.singular %> is not logged in" do
       conn = build_conn()
       conn = get(conn, ~p"<%= schema.route_prefix %>/settings")
-      assert redirected_to(conn) == ~p"<%= schema.route_prefix %>/log_in"
+      assert redirected_to(conn) == ~p"<%= schema.route_prefix %>/log-in"
     end
   end
 
@@ -96,7 +96,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     end
   end
 
-  describe "GET <%= schema.route_prefix %>/settings/confirm_email/:token" do
+  describe "GET <%= schema.route_prefix %>/settings/confirm-email/:token" do
     setup %{<%= schema.singular %>: <%= schema.singular %>} do
       email = unique_<%= schema.singular %>_email()
 
@@ -109,7 +109,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     end
 
     test "updates the <%= schema.singular %> email once", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>, token: token, email: email} do
-      conn = get(conn, ~p"<%= schema.route_prefix %>/settings/confirm_email/#{token}")
+      conn = get(conn, ~p"<%= schema.route_prefix %>/settings/confirm-email/#{token}")
       assert redirected_to(conn) == ~p"<%= schema.route_prefix %>/settings"
 
       assert Phoenix.Flash.get(conn.assigns.flash, :info) =~
@@ -118,7 +118,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       refute <%= inspect context.alias %>.get_<%= schema.singular %>_by_email(<%= schema.singular %>.email)
       assert <%= inspect context.alias %>.get_<%= schema.singular %>_by_email(email)
 
-      conn = get(conn, ~p"<%= schema.route_prefix %>/settings/confirm_email/#{token}")
+      conn = get(conn, ~p"<%= schema.route_prefix %>/settings/confirm-email/#{token}")
 
       assert redirected_to(conn) == ~p"<%= schema.route_prefix %>/settings"
 
@@ -127,7 +127,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     end
 
     test "does not update email with invalid token", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>} do
-      conn = get(conn, ~p"<%= schema.route_prefix %>/settings/confirm_email/oops")
+      conn = get(conn, ~p"<%= schema.route_prefix %>/settings/confirm-email/oops")
       assert redirected_to(conn) == ~p"<%= schema.route_prefix %>/settings"
 
       assert Phoenix.Flash.get(conn.assigns.flash, :error) =~
@@ -138,8 +138,8 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
     test "redirects if <%= schema.singular %> is not logged in", %{token: token} do
       conn = build_conn()
-      conn = get(conn, ~p"<%= schema.route_prefix %>/settings/confirm_email/#{token}")
-      assert redirected_to(conn) == ~p"<%= schema.route_prefix %>/log_in"
+      conn = get(conn, ~p"<%= schema.route_prefix %>/settings/confirm-email/#{token}")
+      assert redirected_to(conn) == ~p"<%= schema.route_prefix %>/log-in"
     end
   end
 end
diff --git a/priv/templates/phx.gen.auth/settings_live_test.exs b/priv/templates/phx.gen.auth/settings_live_test.exs
index e4a25d1f2..32f4ebd92 100644
--- a/priv/templates/phx.gen.auth/settings_live_test.exs
+++ b/priv/templates/phx.gen.auth/settings_live_test.exs
@@ -1,4 +1,4 @@
-defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>SettingsLiveTest do
+defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.SettingsTest do
   use <%= inspect context.web_module %>.ConnCase<%= test_case_options %>
 
   alias <%= inspect context.module %>
@@ -20,7 +20,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       assert {:error, redirect} = live(conn, ~p"<%= schema.route_prefix %>/settings")
 
       assert {:redirect, %{to: path, flash: flash}} = redirect
-      assert path == ~p"<%= schema.route_prefix %>/log_in"
+      assert path == ~p"<%= schema.route_prefix %>/log-in"
       assert %{"error" => "You must log in to access this page."} = flash
     end
   end
@@ -172,7 +172,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     end
 
     test "updates the <%= schema.singular %> email once", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>, token: token, email: email} do
-      {:error, redirect} = live(conn, ~p"<%= schema.route_prefix %>/settings/confirm_email/#{token}")
+      {:error, redirect} = live(conn, ~p"<%= schema.route_prefix %>/settings/confirm-email/#{token}")
 
       assert {:live_redirect, %{to: path, flash: flash}} = redirect
       assert path == ~p"<%= schema.route_prefix %>/settings"
@@ -182,7 +182,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       assert <%= inspect context.alias %>.get_<%= schema.singular %>_by_email(email)
 
       # use confirm token again
-      {:error, redirect} = live(conn, ~p"<%= schema.route_prefix %>/settings/confirm_email/#{token}")
+      {:error, redirect} = live(conn, ~p"<%= schema.route_prefix %>/settings/confirm-email/#{token}")
       assert {:live_redirect, %{to: path, flash: flash}} = redirect
       assert path == ~p"<%= schema.route_prefix %>/settings"
       assert %{"error" => message} = flash
@@ -190,7 +190,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     end
 
     test "does not update email with invalid token", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>} do
-      {:error, redirect} = live(conn, ~p"<%= schema.route_prefix %>/settings/confirm_email/oops")
+      {:error, redirect} = live(conn, ~p"<%= schema.route_prefix %>/settings/confirm-email/oops")
       assert {:live_redirect, %{to: path, flash: flash}} = redirect
       assert path == ~p"<%= schema.route_prefix %>/settings"
       assert %{"error" => message} = flash
@@ -200,9 +200,9 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
     test "redirects if <%= schema.singular %> is not logged in", %{token: token} do
       conn = build_conn()
-      {:error, redirect} = live(conn, ~p"<%= schema.route_prefix %>/settings/confirm_email/#{token}")
+      {:error, redirect} = live(conn, ~p"<%= schema.route_prefix %>/settings/confirm-email/#{token}")
       assert {:redirect, %{to: path, flash: flash}} = redirect
-      assert path == ~p"<%= schema.route_prefix %>/log_in"
+      assert path == ~p"<%= schema.route_prefix %>/log-in"
       assert %{"error" => message} = flash
       assert message == "You must log in to access this page."
     end
diff --git a/test/mix/tasks/phx.gen.auth/injector_test.exs b/test/mix/tasks/phx.gen.auth/injector_test.exs
index 761493c59..6f43d5d98 100644
--- a/test/mix/tasks/phx.gen.auth/injector_test.exs
+++ b/test/mix/tasks/phx.gen.auth/injector_test.exs
@@ -680,7 +680,7 @@ defmodule Mix.Tasks.Phx.Gen.Auth.InjectorTest do
                              </li>
                              <li>
                                <.link
-                                 href={~p"/users/log_out"}
+                                 href={~p"/users/log-out"}
                                  method="delete"
                                  class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"
                                >
@@ -698,7 +698,7 @@ defmodule Mix.Tasks.Phx.Gen.Auth.InjectorTest do
                              </li>
                              <li>
                                <.link
-                                 href={~p"/users/log_in"}
+                                 href={~p"/users/log-in"}
                                  class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"
                                >
                                  Log in
@@ -774,7 +774,7 @@ defmodule Mix.Tasks.Phx.Gen.Auth.InjectorTest do
                              </li>\r
                              <li>\r
                                <.link\r
-                                 href={~p"/users/log_out"}\r
+                                 href={~p"/users/log-out"}\r
                                  method="delete"\r
                                  class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"\r
                                >\r
@@ -792,7 +792,7 @@ defmodule Mix.Tasks.Phx.Gen.Auth.InjectorTest do
                              </li>\r
                              <li>\r
                                <.link\r
-                                 href={~p"/users/log_in"}\r
+                                 href={~p"/users/log-in"}\r
                                  class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"\r
                                >\r
                                  Log in\r
@@ -852,7 +852,7 @@ defmodule Mix.Tasks.Phx.Gen.Auth.InjectorTest do
                        </li>
                        <li>
                          <.link
-                           href={~p"/users/log_out"}
+                           href={~p"/users/log-out"}
                            method="delete"
                            class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"
                          >
@@ -870,7 +870,7 @@ defmodule Mix.Tasks.Phx.Gen.Auth.InjectorTest do
                        </li>
                        <li>
                          <.link
-                           href={~p"/users/log_in"}
+                           href={~p"/users/log-in"}
                            class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"
                          >
                            Log in
@@ -932,7 +932,7 @@ defmodule Mix.Tasks.Phx.Gen.Auth.InjectorTest do
                        </li>\r
                        <li>\r
                          <.link\r
-                           href={~p"/users/log_out"}\r
+                           href={~p"/users/log-out"}\r
                            method="delete"\r
                            class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"\r
                          >\r
@@ -950,7 +950,7 @@ defmodule Mix.Tasks.Phx.Gen.Auth.InjectorTest do
                        </li>\r
                        <li>\r
                          <.link\r
-                           href={~p"/users/log_in"}\r
+                           href={~p"/users/log-in"}\r
                            class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"\r
                          >\r
                            Log in\r
@@ -983,10 +983,10 @@ defmodule Mix.Tasks.Phx.Gen.Auth.InjectorTest do
               <%= if @current_user do %>
                 <li><%= @current_user.email %></li>
                 <li><.link href={~p"/users/settings"}>Settings</.link></li>
-                <li><.link href={~p"/users/log_out"} method="delete">Log out</.link></li>
+                <li><.link href={~p"/users/log-out"} method="delete">Log out</.link></li>
               <% else %>
                 <li><.link href={~p"/users/register"}>Register</.link></li>
-                <li><.link href={~p"/users/log_in"}>Log in</.link></li>
+                <li><.link href={~p"/users/log-in"}>Log in</.link></li>
               <% end %>
             </ul>
           </div>
diff --git a/test/mix/tasks/phx.gen.auth_test.exs b/test/mix/tasks/phx.gen.auth_test.exs
index e252d1167..773ec9a27 100644
--- a/test/mix/tasks/phx.gen.auth_test.exs
+++ b/test/mix/tasks/phx.gen.auth_test.exs
@@ -161,12 +161,12 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
 
                    get "/users/register", UserRegistrationController, :new
                    post "/users/register", UserRegistrationController, :create
-                   get "/users/log_in", UserSessionController, :new
-                   post "/users/log_in", UserSessionController, :create
-                   get "/users/reset_password", UserResetPasswordController, :new
-                   post "/users/reset_password", UserResetPasswordController, :create
-                   get "/users/reset_password/:token", UserResetPasswordController, :edit
-                   put "/users/reset_password/:token", UserResetPasswordController, :update
+                   get "/users/log-in", UserSessionController, :new
+                   post "/users/log-in", UserSessionController, :create
+                   get "/users/reset-password", UserResetPasswordController, :new
+                   post "/users/reset-password", UserResetPasswordController, :create
+                   get "/users/reset-password/:token", UserResetPasswordController, :edit
+                   put "/users/reset-password/:token", UserResetPasswordController, :update
                  end
 
                  scope "/", MyAppWeb do
@@ -174,13 +174,13 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
 
                    get "/users/settings", UserSettingsController, :edit
                    put "/users/settings", UserSettingsController, :update
-                   get "/users/settings/confirm_email/:token", UserSettingsController, :confirm_email
+                   get "/users/settings/confirm-email/:token", UserSettingsController, :confirm_email
                  end
 
                  scope "/", MyAppWeb do
                    pipe_through [:browser]
 
-                   delete "/users/log_out", UserSessionController, :delete
+                   delete "/users/log-out", UserSessionController, :delete
                    get "/users/confirm", UserConfirmationController, :new
                    post "/users/confirm", UserConfirmationController, :create
                    get "/users/confirm/:token", UserConfirmationController, :edit
@@ -194,13 +194,13 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
                  ~r|<.link.*href={~p"/users/settings"}.*>|s
 
         assert file =~
-                 ~r|<.link.*href={~p"/users/log_out"}.*method="delete".*>|s
+                 ~r|<.link.*href={~p"/users/log-out"}.*method="delete".*>|s
 
         assert file =~
                  ~r|<.link.*href={~p"/users/register"}.*>|s
 
         assert file =~
-                 ~r|<.link.*href={~p"/users/log_in"}.*>|s
+                 ~r|<.link.*href={~p"/users/log-in"}.*>|s
       end)
 
       assert_file("test/support/conn_case.ex", fn file ->
@@ -249,20 +249,20 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
         assert file =~ ~s|deliver(user.email, "Update email instructions",|
       end)
 
-      assert_file("lib/my_app_web/live/user_registration_live.ex")
-      assert_file("test/my_app_web/live/user_registration_live_test.exs")
-      assert_file("lib/my_app_web/live/user_login_live.ex")
-      assert_file("test/my_app_web/live/user_login_live_test.exs")
-      assert_file("lib/my_app_web/live/user_reset_password_live.ex")
-      assert_file("test/my_app_web/live/user_reset_password_live_test.exs")
-      assert_file("lib/my_app_web/live/user_forgot_password_live.ex")
-      assert_file("test/my_app_web/live/user_forgot_password_live_test.exs")
-      assert_file("lib/my_app_web/live/user_settings_live.ex")
-      assert_file("test/my_app_web/live/user_settings_live_test.exs")
-      assert_file("lib/my_app_web/live/user_confirmation_live.ex")
-      assert_file("test/my_app_web/live/user_confirmation_live_test.exs")
-      assert_file("lib/my_app_web/live/user_confirmation_instructions_live.ex")
-      assert_file("test/my_app_web/live/user_confirmation_instructions_live_test.exs")
+      assert_file("lib/my_app_web/live/user_live/registration.ex")
+      assert_file("test/my_app_web/live/user_live/registration_test.exs")
+      assert_file("lib/my_app_web/live/user_live/login.ex")
+      assert_file("test/my_app_web/live/user_live/login_test.exs")
+      assert_file("lib/my_app_web/live/user_live/reset_password.ex")
+      assert_file("test/my_app_web/live/user_live/reset_password_test.exs")
+      assert_file("lib/my_app_web/live/user_live/forgot_password.ex")
+      assert_file("test/my_app_web/live/user_live/forgot_password_test.exs")
+      assert_file("lib/my_app_web/live/user_live/settings.ex")
+      assert_file("test/my_app_web/live/user_live/settings_test.exs")
+      assert_file("lib/my_app_web/live/user_live/confirmation.ex")
+      assert_file("test/my_app_web/live/user_live/confirmation_test.exs")
+      assert_file("lib/my_app_web/live/user_live/confirmation_instructions.ex")
+      assert_file("test/my_app_web/live/user_live/confirmation_instructions_test.exs")
 
       assert_file("lib/my_app_web/user_auth.ex")
       assert_file("test/my_app_web/user_auth_test.exs")
@@ -290,13 +290,13 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
 
                    live_session :redirect_if_user_is_authenticated,
                      on_mount: [{MyAppWeb.UserAuth, :redirect_if_user_is_authenticated}] do
-                     live "/users/register", UserRegistrationLive, :new
-                     live "/users/log_in", UserLoginLive, :new
-                     live "/users/reset_password", UserForgotPasswordLive, :new
-                     live "/users/reset_password/:token", UserResetPasswordLive, :edit
+                     live "/users/register", UserLive.Registration, :new
+                     live "/users/log-in", UserLive.Login, :new
+                     live "/users/reset-password", UserLive.ForgotPassword, :new
+                     live "/users/reset-password/:token", UserLive.ResetPassword, :edit
                    end
 
-                   post "/users/log_in", UserSessionController, :create
+                   post "/users/log-in", UserSessionController, :create
                  end
 
                  scope "/", MyAppWeb do
@@ -304,20 +304,20 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
 
                    live_session :require_authenticated_user,
                      on_mount: [{MyAppWeb.UserAuth, :ensure_authenticated}] do
-                     live "/users/settings", UserSettingsLive, :edit
-                     live "/users/settings/confirm_email/:token", UserSettingsLive, :confirm_email
+                     live "/users/settings", UserLive.Settings, :edit
+                     live "/users/settings/confirm-email/:token", UserLive.Settings, :confirm_email
                    end
                  end
 
                  scope "/", MyAppWeb do
                    pipe_through [:browser]
 
-                   delete "/users/log_out", UserSessionController, :delete
+                   delete "/users/log-out", UserSessionController, :delete
 
                    live_session :current_user,
                      on_mount: [{MyAppWeb.UserAuth, :mount_current_user}] do
-                     live "/users/confirm/:token", UserConfirmationLive, :edit
-                     live "/users/confirm", UserConfirmationInstructionsLive, :new
+                     live "/users/confirm/:token", UserLive.Confirmation, :edit
+                     live "/users/confirm", UserLive.ConfirmationInstructions, :new
                    end
                  end
                """
@@ -328,13 +328,13 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
                  ~r|<\.link.*href={~p"/users/settings"}.*>|s
 
         assert file =~
-                 ~r|<\.link.*href={~p"/users/log_out"}.*method="delete".*>|s
+                 ~r|<\.link.*href={~p"/users/log-out"}.*method="delete".*>|s
 
         assert file =~
                  ~r|<\.link.*href={~p"/users/register"}.*>|s
 
         assert file =~
-                 ~r|<\.link.*href={~p"/users/log_in"}.*>|s
+                 ~r|<\.link.*href={~p"/users/log-in"}.*>|s
       end)
 
       assert_file("test/support/conn_case.ex", fn file ->
@@ -366,13 +366,13 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
                  ~r|<.link.*href={~p"/users/settings"}.*>|s
 
         assert file =~
-                 ~r|<.link.*href={~p"/users/log_out"}.*method="delete".*>|s
+                 ~r|<.link.*href={~p"/users/log-out"}.*method="delete".*>|s
 
         assert file =~
                  ~r|<.link.*href={~p"/users/register"}.*>|s
 
         assert file =~
-                 ~r|<.link.*href={~p"/users/log_in"}.*>|s
+                 ~r|<.link.*href={~p"/users/log-in"}.*>|s
       end)
 
       assert_file("lib/my_app_web/router.ex", fn file ->
@@ -387,13 +387,13 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
 
                    live_session :redirect_if_user_is_authenticated,
                      on_mount: [{MyAppWeb.UserAuth, :redirect_if_user_is_authenticated}] do
-                     live "/users/register", UserRegistrationLive, :new
-                     live "/users/log_in", UserLoginLive, :new
-                     live "/users/reset_password", UserForgotPasswordLive, :new
-                     live "/users/reset_password/:token", UserResetPasswordLive, :edit
+                     live "/users/register", UserLive.Registration, :new
+                     live "/users/log-in", UserLive.Login, :new
+                     live "/users/reset-password", UserLive.ForgotPassword, :new
+                     live "/users/reset-password/:token", UserLive.ResetPassword, :edit
                    end
 
-                   post "/users/log_in", UserSessionController, :create
+                   post "/users/log-in", UserSessionController, :create
                  end
 
                  scope "/", MyAppWeb do
@@ -401,20 +401,20 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
 
                    live_session :require_authenticated_user,
                      on_mount: [{MyAppWeb.UserAuth, :ensure_authenticated}] do
-                     live "/users/settings", UserSettingsLive, :edit
-                     live "/users/settings/confirm_email/:token", UserSettingsLive, :confirm_email
+                     live "/users/settings", UserLive.Settings, :edit
+                     live "/users/settings/confirm-email/:token", UserLive.Settings, :confirm_email
                    end
                  end
 
                  scope "/", MyAppWeb do
                    pipe_through [:browser]
 
-                   delete "/users/log_out", UserSessionController, :delete
+                   delete "/users/log-out", UserSessionController, :delete
 
                    live_session :current_user,
                      on_mount: [{MyAppWeb.UserAuth, :mount_current_user}] do
-                     live "/users/confirm/:token", UserConfirmationLive, :edit
-                     live "/users/confirm", UserConfirmationInstructionsLive, :new
+                     live "/users/confirm/:token", UserLive.Confirmation, :edit
+                     live "/users/confirm", UserLive.ConfirmationInstructions, :new
                    end
                  end
                """
@@ -434,13 +434,13 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
                  ~r|<.link.*href={~p"/users/settings"}.*>|s
 
         assert file =~
-                 ~r|<.link.*href={~p"/users/log_out"}.*method="delete".*>|s
+                 ~r|<.link.*href={~p"/users/log-out"}.*method="delete".*>|s
 
         assert file =~
                  ~r|<.link.*href={~p"/users/register"}.*>|s
 
         assert file =~
-                 ~r|<.link.*href={~p"/users/log_in"}.*>|s
+                 ~r|<.link.*href={~p"/users/log-in"}.*>|s
       end)
 
       assert_file("lib/my_app_web/router.ex", fn file ->
@@ -455,12 +455,12 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
 
                    get "/users/register", UserRegistrationController, :new
                    post "/users/register", UserRegistrationController, :create
-                   get "/users/log_in", UserSessionController, :new
-                   post "/users/log_in", UserSessionController, :create
-                   get "/users/reset_password", UserResetPasswordController, :new
-                   post "/users/reset_password", UserResetPasswordController, :create
-                   get "/users/reset_password/:token", UserResetPasswordController, :edit
-                   put "/users/reset_password/:token", UserResetPasswordController, :update
+                   get "/users/log-in", UserSessionController, :new
+                   post "/users/log-in", UserSessionController, :create
+                   get "/users/reset-password", UserResetPasswordController, :new
+                   post "/users/reset-password", UserResetPasswordController, :create
+                   get "/users/reset-password/:token", UserResetPasswordController, :edit
+                   put "/users/reset-password/:token", UserResetPasswordController, :update
                  end
 
                  scope "/", MyAppWeb do
@@ -468,13 +468,13 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
 
                    get "/users/settings", UserSettingsController, :edit
                    put "/users/settings", UserSettingsController, :update
-                   get "/users/settings/confirm_email/:token", UserSettingsController, :confirm_email
+                   get "/users/settings/confirm-email/:token", UserSettingsController, :confirm_email
                  end
 
                  scope "/", MyAppWeb do
                    pipe_through [:browser]
 
-                   delete "/users/log_out", UserSessionController, :delete
+                   delete "/users/log-out", UserSessionController, :delete
                    get "/users/confirm", UserConfirmationController, :new
                    post "/users/confirm", UserConfirmationController, :create
                    get "/users/confirm/:token", UserConfirmationController, :edit
@@ -526,7 +526,7 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
                  ~r|<\.link.*href={~p"/warehouse/users/register"}.*>|s
 
         assert file =~
-                 ~r|<\.link.*href={~p"/warehouse/users/log_in"}.*>|s
+                 ~r|<\.link.*href={~p"/warehouse/users/log-in"}.*>|s
       end)
 
       assert_file(
@@ -548,13 +548,13 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
                  ~r|<\.link.*href={~p"/warehouse/users/settings"}.*>|s
 
         assert file =~
-                 ~r|<\.link.*href={~p"/warehouse/users/log_out"}.*method="delete".*>|s
+                 ~r|<\.link.*href={~p"/warehouse/users/log-out"}.*method="delete".*>|s
 
         assert file =~
                  ~r|<\.link.*href={~p"/warehouse/users/register"}.*>|s
 
         assert file =~
-                 ~r|<\.link.*href={~p"/warehouse/users/log_in"}.*>|s
+                 ~r|<\.link.*href={~p"/warehouse/users/log-in"}.*>|s
       end)
 
       assert_file(
@@ -586,7 +586,7 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
         "lib/my_app_web/controllers/warehouse/user_reset_password_html/edit.html.heex",
         fn file ->
           assert file =~
-                   ~S|<.simple_form :let={f} for={@changeset} action={~p"/warehouse/users/reset_password/#{@token}"}>|
+                   ~S|<.simple_form :let={f} for={@changeset} action={~p"/warehouse/users/reset-password/#{@token}"}>|
         end
       )
 
@@ -594,7 +594,7 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
         "lib/my_app_web/controllers/warehouse/user_reset_password_html/new.html.heex",
         fn file ->
           assert file =~
-                   ~S(<.simple_form :let={f} for={@conn.params["user"]} as={:user} action={~p"/warehouse/users/reset_password"}>)
+                   ~S(<.simple_form :let={f} for={@conn.params["user"]} as={:user} action={~p"/warehouse/users/reset-password"}>)
         end
       )
 
@@ -615,13 +615,13 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
 
       assert_file("lib/my_app_web/controllers/warehouse/user_session_html/new.html.heex", fn file ->
         assert file =~
-                 ~S|<.simple_form :let={f} for={@conn.params["user"]} as={:user} action={~p"/warehouse/users/log_in"}>|
+                 ~S|<.simple_form :let={f} for={@conn.params["user"]} as={:user} action={~p"/warehouse/users/log-in"}>|
 
         assert file =~
                  ~S|<.link navigate={~p"/warehouse/users/register"}|
 
         assert file =~
-                 ~S|<.link href={~p"/warehouse/users/reset_password"}|
+                 ~S|<.link href={~p"/warehouse/users/reset-password"}|
       end)
 
       assert_file(
@@ -677,12 +677,12 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
 
                    get "/users/register", UserRegistrationController, :new
                    post "/users/register", UserRegistrationController, :create
-                   get "/users/log_in", UserSessionController, :new
-                   post "/users/log_in", UserSessionController, :create
-                   get "/users/reset_password", UserResetPasswordController, :new
-                   post "/users/reset_password", UserResetPasswordController, :create
-                   get "/users/reset_password/:token", UserResetPasswordController, :edit
-                   put "/users/reset_password/:token", UserResetPasswordController, :update
+                   get "/users/log-in", UserSessionController, :new
+                   post "/users/log-in", UserSessionController, :create
+                   get "/users/reset-password", UserResetPasswordController, :new
+                   post "/users/reset-password", UserResetPasswordController, :create
+                   get "/users/reset-password/:token", UserResetPasswordController, :edit
+                   put "/users/reset-password/:token", UserResetPasswordController, :update
                  end
 
                  scope "/warehouse", MyAppWeb.Warehouse, as: :warehouse do
@@ -690,13 +690,13 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
 
                    get "/users/settings", UserSettingsController, :edit
                    put "/users/settings", UserSettingsController, :update
-                   get "/users/settings/confirm_email/:token", UserSettingsController, :confirm_email
+                   get "/users/settings/confirm-email/:token", UserSettingsController, :confirm_email
                  end
 
                  scope "/warehouse", MyAppWeb.Warehouse, as: :warehouse do
                    pipe_through [:browser]
 
-                   delete "/users/log_out", UserSessionController, :delete
+                   delete "/users/log-out", UserSessionController, :delete
                    get "/users/confirm", UserConfirmationController, :new
                    post "/users/confirm", UserConfirmationController, :create
                    get "/users/confirm/:token", UserConfirmationController, :edit
@@ -1380,7 +1380,7 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
                 </li>
                 <li>
                   <.link
-                    href={~p"/users/log_out"}
+                    href={~p"/users/log-out"}
                     method="delete"
                     class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"
                   >
@@ -1398,7 +1398,7 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
                 </li>
                 <li>
                   <.link
-                    href={~p"/users/log_in"}
+                    href={~p"/users/log-in"}
                     class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"
                   >
                     Log in
@@ -1444,7 +1444,7 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
                 </li>
                 <li>
                   <.link
-                    href={~p"/users/log_out"}
+                    href={~p"/users/log-out"}
                     method="delete"
                     class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"
                   >
@@ -1462,7 +1462,7 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
                 </li>
                 <li>
                   <.link
-                    href={~p"/users/log_in"}
+                    href={~p"/users/log-in"}
                     class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"
                   >
                     Log in
diff --git a/test/mix/tasks/phx.gen.html_test.exs b/test/mix/tasks/phx.gen.html_test.exs
index b0eb2d309..450e0599b 100644
--- a/test/mix/tasks/phx.gen.html_test.exs
+++ b/test/mix/tasks/phx.gen.html_test.exs
@@ -44,7 +44,7 @@ defmodule Mix.Tasks.Phx.Gen.HtmlTest do
     datetime = %{DateTime.utc_now() | second: 0, microsecond: {0, 6}}
 
     in_tmp_project(config.test, fn ->
-      Gen.Html.run(~w(Blog Post posts title slug:unique votes:integer cost:decimal
+      Gen.Html.run(~w(Blog Post posts title content:text slug:unique votes:integer cost:decimal
                       tags:array:text popular:boolean drafted_at:datetime
                       status:enum:unpublished:published:deleted
                       published_at:utc_datetime
@@ -110,6 +110,7 @@ defmodule Mix.Tasks.Phx.Gen.HtmlTest do
       assert_file(path, fn file ->
         assert file =~ "create table(:posts)"
         assert file =~ "add :title, :string"
+        assert file =~ "add :content, :text"
         assert file =~ "add :status, :string"
         assert file =~ "create unique_index(:posts, [:slug])"
       end)
@@ -151,6 +152,7 @@ defmodule Mix.Tasks.Phx.Gen.HtmlTest do
       assert_file("lib/phoenix_web/controllers/post_html/post_form.html.heex", fn file ->
         assert file =~ ~S(<.simple_form :let={f} for={@changeset} action={@action}>)
         assert file =~ ~s(<.input field={f[:title]} type="text")
+        assert file =~ ~s(<.input field={f[:content]} type="textarea")
         assert file =~ ~s(<.input field={f[:votes]} type="number")
         assert file =~ ~s(<.input field={f[:cost]} type="number" label="Cost" step="any")
 
diff --git a/test/mix/tasks/phx.gen.live_test.exs b/test/mix/tasks/phx.gen.live_test.exs
index e67f57a30..dd5cb4756 100644
--- a/test/mix/tasks/phx.gen.live_test.exs
+++ b/test/mix/tasks/phx.gen.live_test.exs
@@ -55,7 +55,7 @@ defmodule Mix.Tasks.Phx.Gen.LiveTest do
 
   test "generates live resource and handles existing contexts", config do
     in_tmp_live_project config.test, fn ->
-      Gen.Live.run(~w(Blog Post posts title slug:unique votes:integer cost:decimal
+      Gen.Live.run(~w(Blog Post posts title content:text slug:unique votes:integer cost:decimal
                       tags:array:text popular:boolean drafted_at:datetime
                       status:enum:unpublished:published:deleted
                       published_at:utc_datetime
@@ -88,6 +88,7 @@ defmodule Mix.Tasks.Phx.Gen.LiveTest do
       assert_file path, fn file ->
         assert file =~ "create table(:posts)"
         assert file =~ "add :title, :string"
+        assert file =~ "add :content, :text"
         assert file =~ "create unique_index(:posts, [:slug])"
       end
 
@@ -102,6 +103,7 @@ defmodule Mix.Tasks.Phx.Gen.LiveTest do
       assert_file "lib/phoenix_web/live/post_live/form.ex", fn file ->
         assert file =~ ~s(<.simple_form)
         assert file =~ ~s(<.input field={@form[:title]} type="text")
+        assert file =~ ~s(<.input field={@form[:content]} type="textarea")
         assert file =~ ~s(<.input field={@form[:votes]} type="number")
         assert file =~ ~s(<.input field={@form[:cost]} type="number" label="Cost" step="any")
         assert file =~ """
diff --git a/test/support/router_helper.exs b/test/support/router_helper.exs
index d306b3137..9cbf4be23 100644
--- a/test/support/router_helper.exs
+++ b/test/support/router_helper.exs
@@ -11,7 +11,8 @@ defmodule RouterHelper do
 
   defmacro __using__(_) do
     quote do
-      use Plug.Test
+      import Plug.Test
+      import Plug.Conn
       import RouterHelper
     end
   end