LiveView 1.0 removes the client-based phx-feedback-for
annotation for showing and hiding input feedback, such as validation errors. This has been replaced by Phoenix.Component.used_input?/2
, which handles showing and hiding feedback using standard server rendering.
A backwards-compatible shim can be used to maintain phx-feedback-for
in your existing applications:
-
Save the
phx_feedback_dom.js
shim to your localassets/js/phx_feedback_dom.js
. -
Import it into your
assets/js/app.js
. -
Add a new
dom
option to yourLiveSocket
constructor, or wrap the existing value:import {Socket} from "phoenix"; import {LiveSocket} from "phoenix_live_view" import phxFeedbackDom from "./phx_feedback_dom" let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content"); let liveSocket = new LiveSocket("/live", Socket, { params: {_csrf_token: csrfToken}, dom: phxFeedbackDom({}) })
Additionally, the phx-page-loading
attribute has been removed in favor of using the page_loading: true
option to Phoenix.LiveView.JS.push/2
as needed.
While we provide a shim for existing applications relying on phx-feedback-for, you might want to migrate to the new approach.
The following guides you through the necessary changes assuming a project generated
with a recent (Phoenix 1.7), but pre LiveView 1.0 version of the phx generators.
For more general use cases, please also have a look at the documentation for used_input?/1
.
First, ensure that you are using the latest versions of :phoenix_ecto
and :phoenix_html
. At the time of writing:
{:phoenix_ecto, "~> 4.5"},
{:phoenix_html, "~> 4.1"},
-
Adjust the core components to omit the
phx-feedback-for
attribute and thephx-no-feedback
classes. This shows one example for the textarea input, but there are more cases that need to be adjusted accordingly:def input(%{type: "textarea"} = assigns) do ~H""" - <div phx-feedback-for={@name}> + <div> <.label for={@id}><%= @label %></.label> <textarea id={@id} name={@name} class={[ - "mt-2 block w-full rounded-lg text-zinc-900 focus:ring-0 sm:text-sm sm:leading-6", - "min-h-[6rem] phx-no-feedback:border-zinc-300 phx-no-feedback:focus:border-zinc-400", + "mt-2 block w-full rounded-lg text-zinc-900 focus:ring-0 sm:text-sm sm:leading-6 min-h-[6rem]", @errors == [] && "border-zinc-300 focus:border-zinc-400", @errors != [] && "border-rose-400 focus:border-rose-400" ]}
The following regex could be used to find and replace the relevant
phx-no-feedback
classes:/phx-no-feedback:[\w\-\d:]+/
. -
Filter the errors in the initial function for
Phoenix.HTML.FormField
s:def input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do + errors = if Phoenix.Component.used_input?(field), do: field.errors, else: [] assigns |> assign(field: nil, id: assigns.id || field.id) - |> assign(:errors, Enum.map(field.errors, &translate_error(&1))) + |> assign(:errors, Enum.map(errors, &translate_error(&1))) |> assign_new(:name, fn -> if assigns.multiple, do: field.name <> "[]", else: field.name end) |> assign_new(:value, fn -> field.value end) |> input() end
-
You can remove the phx-no-feedback tailwind variant helper from your
tailwind.config.js
:// - plugin(({addVariant}) => addVariant("phx-no-feedback", [".phx-no-feedback&", ".phx-no-feedback &"])), plugin(({addVariant}) => addVariant("phx-click-loading", [".phx-click-loading&", ".phx-click-loading &"])),
The settings page generated by phx.gen.auth creates a form to change the user's email as well as the password.
Because of the way the current password is checked in previous variants of the code, the error message for an invalid
password is not visible when migrating to used_input?
. To make this work, two changes need to be made to the
generated user module:
-
add a new virtual field
:current_password
to the schema:field :hashed_password, :string, redact: true + field :current_password, :string, virtual: true, redact: true
-
cast the
current_password
field in thevalidate_current_password
function:def validate_current_password(changeset, password) do + changeset = cast(changeset, %{current_password: password}, [:current_password]) + if valid_password?(changeset.data, password) do
- Fix inconsistency between
mix format
andmix format --check-formatted
with new curly interpolation syntax (#3590) - Fix unnecessary compile time dependencies when using
attr
/on_mount
/live
(#3592) - Fix crash when testing LiveViews with embedded XML (e.g. SVGs) (#3594)
- Fix type warning when using
follow_redirect
(#3581) - Prevent
phx-trigger-action
from clashing with locked forms (#3591)
- Deduplicate items on
stream/4
/steam_insert/4
(#3599) - Restore scroll position on initial navigation (#3572)
- Change-track non existing keys in maps (#3584)
- Only warn instead of raising when detecting a duplicate ID in LiveViewTest (#3603)
- Raise when duplicate DOM IDs are found when rendering a LiveView during tests to avoid undefined behaviour
- Fix live session verification causing logged errors, push_patch failures, and failed mounts when a cold deploy occurs
- Support
phx-no-curly-interpolation
to disable HEEx curly interpolation in a specific tag body
- Require Elixir v1.14.1+
- Fix live navigation issue where LiveView would attempt a patch on back navigation instead of navigate under certain routing conditions
- Fix live upload issue where large
chunk_size
could cause a chunk timeout on slower connections by properly using the configuredchunk_timeout
on the client - Fix focused inputs losing focus state in some update scenarios
- Fix rare
no component for cid
error when rapidly updating live components under latency - Fix browser back/forward buttons using
patch
instead ofnavigate
, failing to update the page - Fix
inputs_for
not using the passedid
when generating inputs - Do not throw an exception when dispatching a custom input event outside of JS.dispatch
- Fix submitter not being sent when using
JS.push
- Fix form action not being inherited by
to_form
when passing an existing form - Fix live_session not being enforced when patching to the same LiveView under a different route
- Extend HEEx
{@foo}
syntax for interpolating variables inside tag bodies - Support
default
attribute for<.live_title>
component - Add
refute_push_event
toPhoenix.LiveViewTest
- Keep intentional newlines when formatting comments (#3486)
- Support hook
pushEvent
returning a promise - Log a warning when a
push_navigate
fallbacks to a full page reload
- Support nested inputs in
Phoenix.Component.used_input?/1
- Support custom redirect statuses on
Phoenix.LiveView.redirect/2
- Export
createHook
fromphoenix_live_view
to allow CustomElement's to use hooks - Expose programmable JS command interface to hooks for showing, hiding, addClass, etc from a hook which integrates with server DOM patching
- Support targeting inner and closest query selectors in JS commands with
to: {:inner, "a"}
andto: {:closest, "tr"}
, etc. - Throw a more informative error when
JS.dispatch/2
is used with an input event on an invalid target - Validate slot options (prevents typos like
slot :myslot, requird: true
) - Emit
:phoenix, :live_component, :update
telemetry event when a LiveComponent is updated viasend_update/2
- Enhance error recovery during connecting mount to trigger plug_status error pipeline
- Fix
phx-click-loading
classes being incorrectly applied to child elements when issues from a non user click/navigation event - Fix hooks on root LiveComponent container not being torn down and created when the DOM id changes
- Fix select focus states and selects not being updated when focused #3083, #3107
- Fix nested LiveViews inside a stream element
- Fix infinite loading streams in zoomed viewports #3442
- Fix race condition in latency simulator causing messages to be applied out of order
- Fix stream items not reapplying JS commands when joining after a disconnect
- Fix unnecessary remount when navigating back
- Fix character composition mode not working properly in Safari when an input is patched
- Fix
cannot redirect socket on update
error raised erroneously under rare circumstances - Fix upstream morphdom issue that could cause elements being removed from the real DOM instead of a cloned tree while some elements are locked
- Don't dispatch click event when moving mouse away from initial click target
- Fix formatter formatting expressions that are strings with escaped quotes incorrectly
- Deprecate the
name
attribute ofPhoenix.Component.dynamic_tag/1
in favor oftag_name
- Fix issue with phx-submit where the form container would not be updated while awaiting phx-submit acknowledgement
- Support
blocking: false
option to all JS commands that accept:transition
, to avoid blocking DOM updates during the transition
- Fix form recovery when targeting LiveComponents
- Fix formatter incorrectly formatting script tags
- Fix client version mismatch warning for rc.3
- Fix bug allowing focused input to be overwritten on acknowledgement
- Fix issue where locked data-phx-ref containers would still be patched in some cases
- Fix issue where locked data-phx-ref containers would fail to have pending updates like streams applied after acknowledgment
- Fix issue where a LiveComponent issuing live navigation sends an acknowledgement too early before its parent LiveView handle_params diff is sent
- Fix issue allowing phx-remove elements to remain interactive while transitioning out from the page
- Fix bug introduced in rc.1 causing incorrect patching on form elements when awaiting acknowledgements
- Warn when rendering an input named "id"
- Allow form recovery to work on forms in nested LiveViews
- Allow using form/3 with inputs outside the form
- Allow setting page title to an empty string
- Fix warnings on Elixir 1.17
- Fix used input tracking on checkboxes and hidden inputs
- Fix phx-debounce=blur incorrectly sending change event to the next page in some circumstances
- Fix race condition when destroying Live Components while transitions are still running
- Fix page reload when disconnecting LiveSocket if using Bandit
- Fix formatter changing
<%
to<%=
when it shouldn't
- Deprecate
live_flash
in favor ofPhoenix.Flash.get
- Deprecate
push_redirect
in favor ofpush_navigate
phx-capture-click
has been removed (deprecated in 0.17.0)
- Remove
phx-feedback-for
in favor ofPhoenix.Component.used_input?
. See the changelog for a backwards compatiblephx-feedback-for
shim to add to existing applications.
live_component/2
andlive_component/3
helpers (not the function component) have been removed
- Fix attributes of existing stream items not being updated on reset
- Fix nested LiveView within streams becoming empty when reset
- Fix
phx-mounted
firing twice, first on dead render, then on live render, leading to errors when a LiveComponent has not yet mounted - Fix
JS.toggle_class
error when used with a transition - Fix updated form values not being sent in some circumstances when phx-trigger-action is used
- Fix phx-viewport bindings when html or body element has overflow property
- Warn on mismatched client and server versions
- Fix bug introduced in 0.20.15 causing incorrect patching on form elements when awaiting acknowledgements
- Warn when rendering an input named "id"
- Warn on mismatched client and server versions
- Allow form recovery to work on forms in nested LiveViews
- Allow using form/3 with inputs outside the form
- Allow setting page title to an empty string
- Fix warnings on Elixir 1.17
- Fix attributes of existing stream items not being updated on reset
- Fix nested LiveView within streams becoming empty when reset
- Fix
phx-mounted
firing twice, first on dead render, then on live render, leading to errors when a LiveComponent has not yet mounted - Fix
JS.toggle_class
error when used with a transition - Fix phx-debounce=blur incorrectly sending change event to the next page in some circumstances
- Fix race condition when destroying Live Components while transitions are still running
- Fix page reload when disconnecting LiveSocket if using Bandit
- Fix formatter changing
<%
to<%=
when it shouldn't - Fix updated form values not being sent in some circumstances when phx-trigger-action is used
- Fix phx-viewport bindings when html or body element has overflow property
- Deprecate
live_flash
in favor ofPhoenix.Flash.get
- Deprecate
push_redirect
in favor ofpush_navigate
phx-capture-click
has been removed (deprecated in 0.17.0)live_component/2
andlive_component/3
helpers (not the function component) have been removed
- Fix warning caused by optional Floki dependency
- Fix LiveComponent rendering bug causing elements to disappear when a LiveComponent child is removed and added back by the server
- Warn when accessing the socket in a function passed to assign_async / start_async
- Phoenix LiveView requires Elixir v1.13+
- Do not send Telemetry metadata as Logger event, this avoids the metadata from being accidentally copied to other processes
- Ensure LiveViewTest does not crash on IDs with foreign characters, such as question marks
- Fix a bug where LiveViewTest could not perform a connected mount on a page with certain streams
- Fix auto uploads with invalid entries incorrectly proceeding with a form submit instead of halting, causing entries in progress errors
- Fix auto upload entries failing to be uploaded on submit after moving into a valid state, such as falling within
max_entries
- Fix TagEngine clause warning
- Fix cancelled uploads being re-added
- Fix form submits for previously submitted invalid upload entries causing errors instead of preflighted new upload entries
- Fix HTML formatter not respecting phx-no-format for script tags
- Add additional HEEx debug annotations for the caller locations of function component invocations
- Abandon form recovery if recovery event fails
- Fix error in LiveViewTest when a
phx-update="ignore"
container is added dynamically to the DOM
- Fix live uploader issue when a form contained more than one
<.live_file_input>
- Fix phx-remove on re-added stream items trigging the remove when it should not
- Fix js error attempting to re-order an element that does not exist in the DOM
- Align LiveViewTest with JavaScript DOM patching behavior for phx-update="ignore" when updating attributes in LiveViewTest
- Fix phx-skip containers leaking into DOM on first patch in some cases (#3117)
- Fix phx-feedback-for failing to be properly updated in some cases (#3122)
- Fix stream items being excluded in LiveViewTest
- Fix stream items failing to properly update nested streams or LiveComponents
- Fix debounce/blur regression causing unexpected events to be sent
- Deprecate
phx-feedback-group
introduced in the previous release, the goal is to move feedback handling into Elixir and out of the DOM
- Fix blur event on phx-debounce being dispatched incorrectly
- Fix
open_browser
not working on WSL for project under UNIX file systems - Match browser stream insert ordering behavior in
LiveViewTest
- Fix
phx-click-away
not working when element is partially hidden - Fix
phx-feedback-for
classes not being applied in some cases - Fix form submitter failing to be sent as key/value pair in some cases
- Fix null form reference causing errors on some DOM patches
- Fix phx-remove on sticky LiveViews
- Fix phx-disabled-with not restoring button disabled state on empty diff acknowledgement
- Fix stream reset not ordering items correctly
- Send
{:shutdown, :cancel}
tohandle_async/3
oncancel_async
- Prevent events from child LiveViews from bubbling up to root LiveView when child is not mounted yet
- Fix
phx-mounted
being called twice for stream items - Never move existing stream items if they already exist (use stream_delete and then stream_insert instead)
- Fix live component rendering breaking when the server adds a component back that was pruned by the client (#3026)
- Allow redirect from upload progress callback
- Fix nested components getting skipped when resetting a stream
- Fix nested components getting skipped in LiveComponents
- Fix stream limits not being applied correctly when bulk inserting
- Fix click-away being called incorrectly on form submits
- Fix inconsistencies between LiveViewTest and browser stream implementations
- Fix phx-feedback-for being reapplied when there are multiple inputs with the same name
- Ensure phx-update="ignore" behaves consistently: updates from the server to the element's content and attributes are ignored, except for data attributes
- Add
JS.toggle_class
- Add
JS.toggle_attribute
- Force update select options when the options changed from the server while a select has focus
- Introduce
phx-feedback-group
for handling feedback for composite input groups - Add
validate_attrs
to slots - Support
phx-viewport
bindings in scrollable containers - Perform client redirect when trying to live nav from dead client to avoid extra round trip
- Allow regular buttons with name/value attributes to send form events and adjusted dynamic form documentation to reflect this
- Allow form attribute on
live_file_input
live_component/2
andlive_component/3
helpers (not the function component) have been removed
- Fix phx-viewport bindings failing to fire after navigation
- Preserve order of appended items in stream in
LiveViewTest
- Fix order of items on client when resetting a stream to existing set of items
- Support
JS.push
from dead views
- Fix JavaScript error when submitting a form that has in progress uploads
- Fix JS command
:target
failing to work when used as phx-submit or phx-change with a selector-based target - Fix
JS.focus()
failing to focus negative tabindex - Fix
LiveViewTest
failing to remove items after stream reset - Fix
phx-window-blur
andphx-window-focus
events not firing - Fix SVG anchor links throwing errors when clicked
- Speed up DOM patching performance 3-30x 🔥
- Support
handle_async
lifecycle callback - Extend visibility checks for phx-click-away to better handle whether an element is visible in the viewport or not
- Allow
JS.patch
andJS.navigate
to be tested withrender_click
- Support
:supervisor
option toassign_async
andstart_async
- Deprecate
phx-update="append"
andphx-update="prepend"
in favor ofphx-update="stream"
- Fix error with live uploads
auto_upload: true
when a file fails to preflight - Fix error with live uploads where an early exit can cause a map key error
- Fix match error on live navigation when reconnecting from client
- Support new
meta()
method on File/Blob subclasses on JavaScript client to allow the client to pass arbitrary metadata when usingupload/uploadTo
from hook. The%UploadEntry{}
's newclient_meta
field is populated from this information. - Improve void tagging and error messages
- Deprecate the
~L
sigil in favor of~H
- Deprecate
preload/1
in LiveComponent in favor ofupdate_many/1
- Deprecate
live_component/2-3
in favor of<.live_component />
- Deprecate
live_patch
in favor of<.link patch={...} />
- Deprecate
live_redirect
in favor of<.link navigate={...} />
- Deprecate
live_title_tag
in favor of<.live_title />
- Remove previously deprecated
render_block/2
in favor ofrender_slot/2
- Remove previously deprecated
live_img_preview/2
in favor of<.live_img_preview />
- Remove previously deprecated
live_file_input/2
in favor of<.live_file_input />
- Fix uploads with
auto_upload: true
failing to propagate errors when any individual entry is invalid - Fix uploads with
auto_upload: true
failing to auto upload valid entries errors when any individual entry is invalid - Fix error on form recovery with
auto_upload: true
- Fix issue on form recovery where hidden inputs would be selected by mistake
- Fix form recovery when phx-change is a JS command
- Fix stream reset on nested live components with nested streams
- Fix window location resetting to null when using nested LiveView on connection error
- Fix anchors within contenteditable causing LiveSocket disconnects
- Add heex debug annotations via
config :phoenix_live_view, debug_heex_annotations: true
, which provides special HTML comments that wrap around rendered components to help you identify where markup in your HTML document is rendered within your function component tree - Add
assign_async
,start_async
,<.async_result>
and,AsyncResult
for declaratively handling async operations in a LiveView or LiveComponent. - Supporting passing
@myself
forPhoenix.LiveView.send_update/3
- Support change tracking on Access.get
- Allow overriding
id
of<.live_img_preview>
- The
close/1
callback ofPhoenix.LiveView.UploadWriter
is nowclose/2
with the close reason passed as the second argument. - The
write_chunk
callback ofPhoenix.LiveView.UploadWriter
must now return the updated writer state when an error occurs. Instead of{:error, reason}
, return{:error, reason, new_state}
.
- Pass close reason to
Phoenix.LiveView.UploadWriter
close. - Dispatch
phx:navigate
window events when LiveView changes the history state
- Call
Phoenix.LiveView.UploadWriter
close callback when LiveView goes down or connection is lost - Fix JS.patch to a Phoenix router scope with
:host
causing errors - Fix immediate navigation after patch not updating URL
- Fix stream reset on nested streams inside live components causing nested stream children to be removed
- Introduce
Phoenix.LiveView.UploadWriter
- Fix
push_event
inside component update not being sent in some cases - Bring back accidentally deprecated
upload_errors/1
- Fix issue when
<input name="value" />
is used
- Allow
accept
attribute on<.live_file_input>
to override default values
- Fix issue causing anchor clicks to disconnect LV when they were already handled via
preventDefault()
by other scripts
- Drop support for passing an id to the
phx-feedback-for
attribute. An input name must be passed instead. - Remove previously deprecated
let
attribute. Use:let
instead - Remove previously deprecated
<%= live_img_preview(entry) %>
. Use<.live_img_preview entry={entry} />
instead - Remove previously deprecated
<%= live_file_input(upload) %>
. Use<.live_file_input upload={upload} />
instead - Remove previously deprecated
<%= live_component(Component) %>
. Use<.live_component module={Component} id=\"hello\" />
instead - Don't convert underscores to dashes automatically when rendering HTML attributes. Use dashes or underscores where appropriate instead.
- Support stream resets with bulk insert operations
- Support ordered inputs within
inputs_for
, to pair with Ecto's newsort_param
anddrop_param
casting - Send form phx-value's on form events
- Deprecate passing
:dom_id
tostream/4
in favor ofstream_configure/3
- Deprecate
render_block/2
in favor ofrender_slot/2
- Deprecate
<%= live_img_preview(entry, opts) %>
. Use<.live_img_preview entry={entry} {opts} />
- Deprecate
<%= live_file_input(upload, opts) %>
. Use<.live_file_input upload={upload} {opts} />
- Deprecate stateless LiveComponent in favor of function components or in favor of
<.live_component id={...} />
(note theid
is required)
- Fix LiveView disconnects when clicking a
download
link - Fix stream deletes not being sent on nested for comprehensions
- Fix
phx-disconnected
bindings not firing on mount failures - Support form recovery on forms with only hidden inputs
- Allow
:live_action
to be assigned in a component - Only filter internal function component attributes in
assigns_to_attributes
- Only include submitter with name
- Add
JS.exec
command for executing commands defined on other element attributes
- Fix callbacks like
handle_info
failing to be invoked in development after a code change with the Phoenix code reloader
- Support
submitter
on form submit events. - Avoid compile-time dependency for
attr
when referencing structs - Validate reserved assigns. Attempting to assign
:uploads
,:streams
,:live_action
,:socket
,:myself
will now raise in LiveView and LiveComponent
- Support streams in Live Components
- Optimize plug error translation when a Plug.Exception is raised over connected LiveView
- Fix formatter issues when there are multiple HTML comments
- Fix
JS.transition
applying incorrect classes
- Reset phx-feedback-for errors on
type="reset"
inputs and buttons
- Fix LiveViewTest failing to find main live view
- Improve error message when failing to use Phoenix.Component
- Introduce streams for efficiently handling large collections
- Allow replies from
:handle_event
lifecycle hooks - Add
<.inputs_for>
component toPhoenix.Component
- Support replies on lifecycle
:handle_event
hooks
- Fix change tracking when re-assigning a defaulted attribute to same default value
- Fix upload drag and drop failing to worka after using file select dialog
- Fix form recovery when form's first input is phx-change
- Fix socket unloading connection for forms that have defaulted prevented
- Fix svg tags with href incorrectly unloading socket on click
- Fix form submits with
target="_blank"
incorrectly unloading socket on submit
- Fix regular form submits failing to be dispatched
- Restore scroll position on back when previous navigation was live patch
- Fix live layout not being applied until connected render
- Fix live layout not being applied when passed to
:live_session
during disconnect render - Fix external anchor clicks and links with hashes incorrectly unloading socket
- Fix external anchor click unloading on external click
- Fix external anchor click unloading socket
- Support string upload name to support dynamically generated
allow_upload
's
- Fix nested LiveView race condition on live patch causing nested child to skip updates in some cases
- Fix browser history showing incorrect title when using live navigation with
@page_title
- Fix undefined _target param when using
JS.push
for form changes - Fix
phx-no-feedback
missing from inputs added after a form submit - Fix
phx-disconnected
events firing when navigating away or submitting external forms
- Add
embed_templates
toPhoenix.Component
for embedding template files as function components - Raise on global slot attributes
- Fix bug on slots when passing multiple slot entries with mix if/for syntax
- Fix match error when defining
:values
before:default
- Allow tuples in external redirects
- Fix race condition on dispatching click away when enter is pressed
- Fix formatter breaking inline blocks when surrounded by text without whitespace
- Add
intersperse
component for rendering a separator between an enumerable
- Fix phx-loading class being applied to dead views
- Fix
<.live_img_preview />
causing invalid attribute errors on uploads - Do not fire phx events when element is disabled
- Support
:include
option to extend global attributes on a case-by-case basis - Warn when accessing a variable binding defined outside of
~H
LiveView v0.18 includes a major new feature in the form of declarative assigns with new attr
and slot
APIs for specifying which attributes a function component supports, the type,
and default values. Attributes and slots are compile-time verified and emit warnings (requires Elixir v1.14.0+).
v0.18 includes a number of new function components which replace their EEx expression
counterparts <%= ... %>
. For example, live_redirect
, live_patch
, and Phoenix.HTML's
link
have been replaced by a unified Phoenix.Component.link/1
function component:
<.link href="https://myapp.com">my app</.link>
<.link navigate={@path}>remount</.link>
<.link patch={@path}>patch</.link>
Those new components live in the Phoenix.Component
module. Phoenix.LiveView.Helpers
itself has been soft deprecated and all relevant functionality has been migrated.
You must import Phoenix.Component
where you previously imported Phoenix.LiveView.Helpers
when upgrading. You may also need to import Phoenix.Component
where you also imported Phoenix.LiveView
and some of its functions have been moved to Phoenix.Component
.
Additionally, the special let
attribute on function components have been deprecated by
a :let
usage.
live_redirect
- deprecate in favor of new<.link navigate={..}>
component ofPhoenix.Component
live_patch
- deprecate in favor of new<.link patch={..}>
component ofPhoenix.Component
push_redirect
- deprecate in favor of newpush_navigate
function onPhoenix.LiveView
- [Component] Add declarative assigns with compile-time verifications and warnings via
attr
/slot
- [Component] Add new attrs
:let
and:for
, and:if
with HTML tag, function component, and slot support. We still supportlet
but the formatter will convert it to:let
and soon it will be deprecated. - [Component] Add
dynamic_tag
function component - [Component] Add
link
function component - [Component] Add
focus_wrap
function component to wrap focus around content like modals and dialogs for accessibility - [Logger] Add new LiveView logger with telemetry instrumentation for lifecycle events
- [JS] Add new JS commands for
focus
,focus_first
,push_focus
, andpop_focus
for accessibility - [Socket] Support sharing
Phoenix.LiveView.Socket
with regular channels viause Phoenix.LiveView.Socket
- Add
_live_referer
connect param for handlingpush_navigate
referral URL - Add new
phx-connected
andphx-disconnected
bindings for reacting to lifecycle changes - Add dead view support for JS commands
- Add dead view support for hooks
- Fix external upload issue where listeners are not cleaned up when an external failure happens on the client
- Do not debounce
phx-blur
- Add support for upcoming Phoenix 1.7 flash interface
- Add
replaceTransport
to LiveSocket
- Cancel debounced events from firing after a live navigation event
- Fix hash anchor failing to scroll to anchor element on live navigation
- Do not debounce
phx-blur
events
- [Formatter] Preserve single quote delimiter on attrs
- [Formatter] Do not format inline elements surrounded by texts without whitespaces
- [Formatter] Keep text and eex along when there isn't a whitespace
- [Formatter] Fix intentional line breaks after eex expressions
- [Formatter] Handle self close tags as inline
- [Formatter] Do not format inline elements without whitespaces among them
- [Formatter] Do not format when attr contenteditable is present
- [Formatter] Introduce special attr phx-no-format to skip formatting
- Fix sticky LiveViews failing to be patched during live navigation
- Do not raise on dynamic
phx-update
value
- Add HEEx formatter
- Support
phx-change
on individual inputs - Dispatch
MouseEvent
on client - Add
:bubbles
option toJS.dispatch
to control event bubbling - Expose underlying
liveSocket
instance on hooks - Enable client debug by default on localhost
- Fix hook and sticky LiveView issues caused by back-to-back live redirects from mount
- Fix hook destroyed callback failing to be invoked for children of phx-remove in some cases
- Do not failsafe reload the page on push timeout if disconnected
- Do not bubble navigation click events to regular phx-click's
- No longer generate
csrf_token
for forms without action, reducing the payload during phx-change/phx-submit events
- Optimize nested for comprehension diffs
- Fix error when
live_redirect
links are clicked when not connected in certain cases
- Add
JS.set_attribute
andJS.remove_attribute
- Add
sticky: true
option tolive_render
to maintain a nested child on across live redirects - Dispatch
phx:show-start
,phx:show-end
,phx:hide-start
andphx:hide-end
onJS.show|hide|toggle
- Add
get_connect_info/2
that also works on disconnected render - Add
LiveSocket
constructor options for configuration failsafe behavior via newmaxReloads
,reloadJitterMin
,reloadJitterMax
,failsafeJitter
options
- Show form errors after submit even when no changes occur on server
- Fix
phx-disable-with
failing to disable elements outside of forms - Fix phx ref tracking leaving elements in awaiting state when targeting an external LiveView
- Fix diff on response failing to await for active transitions in certain cases
- Fix
phx-click-away
not respectingphx-target
- Fix "disconnect" broadcast failing to failsafe refresh the page
- Fix
JS.push
with:target
failing to send to correct component in certain cases
- Deprecate
Phoenix.LiveView.get_connect_info/1
in favor ofget_connect_info/2
- Deprecate
Phoenix.LiveViewTest.put_connect_info/2
in favor of calling the relevant functions inPlug.Conn
- Deprecate returning "raw" values from upload callbacks on
Phoenix.LiveView.consume_uploaded_entry/3
andPhoenix.LiveView.consume_uploaded_entries/3
. The callback must return either{:ok, value}
or{:postpone, value}
. Returning any other value will emit a warning.
- Do not trigger
phx-click-away
if element is not visible - Fix
phx-remove
failing to tear down nested live children
- Fix variable scoping issues causing various content block or duplication rendering bugs
- Support 3-tuple for JS class transitions to support staged animations where a transition class is applied with a starting and ending class
- Allow JS commands to be executed on DOM nodes outside of the LiveView container
- Avoid duplicate statics inside comprehension. In previous versions, comprehensions were able to avoid duplication only in the content of their root. Now we recursively traverse all comprehension nodes and send the static only once for the whole comprehension. This should massively reduce the cost of sending comprehensions over the wire
- Fix HTML engine bug causing expressions to be duplicated or not rendered correctly
- Fix HTML engine bug causing slots to not be re-rendered when they should have
- Fix form recovery being sent to wrong target
- Fix HTML engine bug causing attribute expressions to be incorrectly evaluated in certain cases
- Fix show/hide/toggle custom display not being restored
- Fix default
to
target forJS.show|hide|dispatch
- Fix form input targeting
- Fix SVG element support for
phx
binding interactions
The hook API introduced in LiveView 0.16 has been improved based on feedback.
LiveView 0.17 removes the custom module-function callbacks for the
Phoenix.LiveView.on_mount/1
macro and the :on_mount
option for
Phoenix.LiveView.Router.live_session/3
in favor of supporting a custom
argument. For clarity, the module function to be invoked during the mount
lifecycle stage will always be named on_mount/4
.
For example, if you had invoked on_mount/1
like so:
on_mount MyAppWeb.MyHook
on_mount {MyAppWeb.MyHook, :assign_current_user}
and defined your callbacks as:
# my_hook.ex
def mount(_params, _session, _socket) do
end
def assign_current_user(_params, _session, _socket) do
end
Change the callback to:
# my_hook.ex
def on_mount(:default, _params, _session, _socket) do
end
def on_mount(:assign_current_user, _params, _session, _socket) do
end
When given only a module name, the first argument to on_mount/4
will be the
atom :default
.
Stateful LiveComponents (where an :id
is given) must now return HEEx templates
(~H
sigil or .heex
extension). LEEx templates (~L
sigil or .leex
extension)
are no longer supported. This addresses bugs and allows stateful components
to be rendered more efficiently client-side.
Due to a bug in the newly released Safari 15, the previously used .phx-disconnected
class has been replaced by a new .phx-loading
class. The reason for the change is phx.new
included a .phx-disconnected
rule in the generated app.css
which triggers the Safari bug. Renaming the class avoids applying the erroneous rule for existing applications. Folks can upgrade by simply renaming their .phx-disconnected
rules to .phx-loading
.
The new phx-click-away
binding replaces phx-capture-click
and is much more versatile because it can detect "click focus" being lost on containers.
Some functionality that was previously deprecated has been removed:
- Implicit assigns in
live_component
do-blocks is no longer supported - Passing a
@socket
tolive_component
will now raise if possible
- Allow slots in function components: they are marked as
<:slot_name>
and can be rendered with<%= render_slot @slot_name %>
- Add
JS
command for executing JavaScript utility operations on the client with an extended push API - Optimize string attributes:
- If the attribute is a string interpolation, such as
<div class={"foo bar #{@baz}"}>
, only the interpolation part is marked as dynamic - If the attribute can be empty, such as "class" and "style", keep the attribute name as static
- If the attribute is a string interpolation, such as
- Add a function component for rendering
Phoenix.LiveComponent
. Instead of<%= live_component FormComponent, id: "form" %>
, you must now do:<.live_component module={FormComponent} id="form" />
- Fix LiveViews with form recovery failing to properly mount following a reconnect when preceded by a live redirect
- Fix stale session causing full redirect fallback when issuing a
push_redirect
from mount - Add workaround for Safari bug causing
<img>
tags with srcset and video with autoplay to fail to render - Support EEx interpolation inside HTML comments in HEEx templates
- Support HTML tags inside script tags (as in regular HTML)
- Raise if using quotes in attribute names
- Include the filename in error messages when it is not possible to parse interpolated attributes
- Make sure the test client always sends the full URL on
live_patch
/live_redirect
. This mirrors the behaviour of the JavaScript client - Do not reload flash from session on
live_redirect
s - Fix select drop-down flashes in Chrome when the DOM is patched during focus
<%= live_component MyModule, id: @user.id, user: @user %>
is deprecated in favor of<.live_component module={MyModule} id={@user.id} user={@user} />
. Notice the new API requires using HEEx templates. This change allows us to further improve LiveComponent and bring new features such as slots to them.render_block/2
in deprecated in favor ofrender_slot/2
- Improve HEEx error messages
- Relax HTML tag validation to support mixed case tags
- Support self closing HTML tags
- Remove requirement for
handle_params
to be defined for lifecycle hooks
- Fix pushes failing to include channel
join_ref
on messages
- Fix
on_mount
hooks calling view mount before redirecting when the hook issues a halt redirect.
- Improve error messages on tokenization
- Improve error message if
@inner_block
is missing
- Fix
phx-change
form recovery event being sent to wrong component on reconnect when component order changes
- Relax
phoenix_html
dependency requirement - Allow testing functional components by passing a function reference
to
Phoenix.LiveViewTest.render_component/3
- Do not generate CSRF tokens for non-POST forms
- Do not add compile-time dependencies on
on_mount
declarations
LiveView v0.16 optimizes live redirects by supporting navigation purely
over the existing WebSocket connection. This is accomplished by the new
live_session/3
feature of Phoenix.LiveView.Router
. The
security guide has always stressed
the following:
... As we have seen, LiveView begins its life-cycle as a regular HTTP request. Then a stateful connection is established. Both the HTTP request and the stateful connection receives the client data via parameters and session. This means that any session validation must happen both in the HTTP request (plug pipeline) and the stateful connection (LiveView mount) ...
These guidelines continue to be valid, but it is now essential that the
stateful connection enforces authentication and session validation within
the LiveView mount lifecycle because a live_redirect
from the client
will not go through the plug pipeline as a hard-refresh or initial HTTP
render would. This means authentication, authorization, etc that may be
done in the Plug.Conn
pipeline must also be performed within the
LiveView mount lifecycle.
Live sessions allow you to support a shared security model by allowing
live_redirect
s to only be issued between routes defined under the same
live session name. If a client attempts to live redirect to a different
live session, it will be refused and a graceful client-side redirect will
trigger a regular HTTP request to the attempted URL.
See the Phoenix.LiveView.Router.live_session/3
docs for more information
and example usage.
LiveView v0.16 introduces HEEx (HTML + EEx) templates and the concept of function
components via Phoenix.Component
. The new HEEx templates validate the markup in
the template while also providing smarter change tracking as well as syntax
conveniences to make it easier to build composable components.
A function component is any function that receives a map of assigns and returns
a ~H
template:
defmodule MyComponent do
use Phoenix.Component
def btn(assigns) do
~H"""
<button class="btn"><%= @text %></button>
"""
end
end
This component can now be used as in your HEEx templates as:
<MyComponent.btn text="Save">
The introduction of HEEx and function components brings a series of deprecation warnings, some introduced in this release and others which will be added in the future. Note HEEx templates require Elixir v1.12+.
The main deprecation in this release is that the ~L
sigil and the .leex
extension
are now soft-deprecated. The docs have been updated to discourage them and using them
will emit warnings in future releases. We recommend using the ~H
sigil and the .heex
extension for all future templates in your application. You should also plan to migrate
the old templates accordingly using the recommendations below.
Migrating from LEEx
to HEEx
is relatively straightforward. There are two main differences.
First of all, HEEx does not allow interpolation inside tags. So instead of:
<div id="<%= @id %>">
...
</div>
One should use the HEEx syntax:
<div id={@id}>
...
</div>
The other difference is in regards to form_for
. Some templates may do the following:
~L"""
<%= f = form_for @changeset, "#" %>
<%= input f, :foo %>
</form>
"""
However, when converted to ~H
, it is not valid HTML: there is a </form>
tag but
its opening is hidden inside the Elixir code. On LiveView v0.16, there is a function
component named form
:
~H"""
<.form :let={f} for={@changeset}>
<%= input f, :foo %>
</.form>
"""
We understand migrating all templates from ~L
to ~H
can be a daunting task.
Therefore we plan to support ~L
in LiveViews for a long time. However, we can't
do the same for stateful LiveComponents, as some important client-side features and
optimizations will depend on the ~H
sigil. Therefore our recommendation is to
replace ~L
by ~H
first in live components, particularly stateful live components.
Furthermore, stateless live_component
(i.e. live components without an :id
)
will be deprecated in favor of the new function components. Our plan is to support
them for a reasonable period of time, but you should avoid creating new ones in
your application.
LiveView 0.16 removes the :layout
and :container
options from
Phoenix.LiveView.Routing.live/4
in favor of the :root_layout
and :container
options on Phoenix.Router.live_session/3
.
For instance, if you have the following in LiveView 0.15 and prior:
live "/path", MyAppWeb.PageLive, layout: {MyAppWeb.LayoutView, "custom_layout.html"}
Change it to:
live_session :session_name, root_layout: {MyAppWeb.LayoutView, "custom_layout.html"} do
live "/path", MyAppWeb.PageLive
end
On the client, the phoenix_live_view
package no longer provides a default export for LiveSocket
.
If you have the following in your JavaScript entrypoint (typically located at assets/js/app.js
):
import LiveSocket from "phoenix_live_view"
Change it to:
import { LiveSocket } from "phoenix_live_view"
Additionally on the client, the root LiveView element no longer exposes the
LiveView module name, therefore the phx-view
attribute is never set.
Similarly, the viewName
property of client hooks has been removed.
Codebases calling a custom function component/3
should rename it or specify its module to avoid a conflict,
as LiveView introduces a macro with that name and it is special cased by the underlying engine.
- Introduce HEEx templates
- Introduce
Phoenix.Component
- Introduce
Phoenix.Router.live_session/3
for optimized live redirects - Introduce
on_mount
andattach_hook
hooks which provide a mechanism to tap into key stages of the LiveView lifecycle - Add upload methods to client-side hooks
- [Helpers] Optimize
live_img_preview
rendering - [Helpers] Introduce
form
function component which wrapsPhoenix.HTML.form_for
- [LiveViewTest] Add
with_target
for scoping components directly - [LiveViewTest] Add
refute_redirected
- [LiveViewTest] Support multiple
phx-target
values to mirror JS client - [LiveViewTest] Add
follow_trigger_action
- [JavaScript Client] Add
sessionStorage
optionLiveSocket
constructor to support client storage overrides - [JavaScript Client] Do not failsafe reload the page in the background when a tab is unable to connect if the page is not visible
- Make sure components are loaded on
render_component
to ensure all relevant callbacks are invoked - Fix
Phoenix.LiveViewTest.page_title
returningnil
in some cases - Fix buttons being re-enabled when explicitly set to disabled on server
- Fix live patch failing to update URL when live patch link is patched again via
handle_params
within the same callback lifecycle - Fix
phx-no-feedback
class not applied when page is live-patched - Fix
DOMException, querySelector, not a valid selector
when performing DOM lookups on non-standard IDs - Fix select dropdown flashing close/opened when assigns are updated on Chrome/macOS
- Fix error with multiple
live_file_input
in one form - Fix race condition in
showError
causing nullquerySelector
- Fix statics not resolving correctly across recursive diffs
- Fix no function clause matching in
Phoenix.LiveView.Diff.many_to_iodata
- Fix upload input not being cleared after files are uploaded via a component
- Fix channel crash when uploading during reconnect
- Fix duplicate progress events being sent for large uploads
- Implicit assigns when passing a
do-end
block tolive_component
is deprecated - The
~L
sigil and the.leex
extension are now soft-deprecated in favor of~H
and.heex
- Stateless live components (a
live_component
call without an:id
) are deprecated in favor of the new function component feature
- Fix broken webpack build throwing missing morphdom dependency
- Fix live patch failing to update URL when live patch link is patched again from
handle_params
- Fix regression in
LiveViewTest.render_upload/3
when using channel uploads and progress callback - Fix component uploads not being cleaned up on remove
- Fix
KeyError
on LiveView reconnect when an active upload was previously in progress
- Support function components via
component/3
- Optimize progress events to send less messages for larger file sizes
- Allow session and local storage client overrides
- Deprecate
@socket/socket
argument onlive_component/3
call
- Add
upload_errors/1
for returning top-level upload errors
- Fix
consume_uploaded_entry/3
with external uploads causing inconsistent entries state - Fix
push_event
losing events when a single diff produces multiple events from different components - Fix deep merging of component tree sharing
- Fix nested
live_render
's causing remound of child LiveView even when ID does not change - Do not attempt push hook events unless connected
- Fix preflighted refs causing
auto_upload: true
to fail to submit form - Replace single upload entry when
max_entries
is 1 instead of accumulating multiple file selections - Fix
static_path
inopen_browser
failing to load stylesheets
- Fix
push_redirect
back causing timeout on the client
- Remove
beforeDestroy
fromphx-hook
callbacks
- Fix form recovery failing to send input on first connection failure
- Fix hooks not getting remounted after LiveView reconnect
- Fix hooks
reconnected
callback being fired with no prior disconnect
- Ensure all click events bubble for mobile Safari
- Run
consume_uploaded_entries
in LiveView caller process
- Fix hooks not getting remounted after LiveView recovery
- Fix bug causing reload with jitter on timeout from previously closed channel
- Fix component child nodes being lost when component patch goes from single root node to multiple child siblings
- Fix
phx-capture-click
triggering on mouseup during text selection - Fix LiveView
push_event
's not clearing up in components - Fix
<textarea>
being patched by LiveView while focused
- Add live uploads support for file progress, interactive file selection, and direct to cloud support
- Implement
Phoenix.LiveViewTest.open_browser/2
that opens up a browser with the LiveView page
- Remove
@inner_content
in components and introducerender_block
for rendering component@inner_block
- Remove
@live_module
in socket templates in favor of@socket.view
- Make sure URLs are decoded after they are split
- Do not recover forms without inputs
- Fix race condition when components are removed and then immediately re-added before the client can notify their CIDs have been destroyed
- Do not render LiveView if only events/replies have been added to the socket
- Properly merge different components when sharing component subtrees on initial render
- Allow variables inside do-blocks to be tainted
- Fix
push_redirect
from mount hanging on the client and causing a fallback to full page reload when following a clickedlive_redirect
on the client
- Fix compatibility with latest Plug
- Fix
redirect(socket, external: ...)
when returned from an event - Properly follow location hashes on live patch/redirect
- Fix failure in
Phoenix.LiveViewTest
whenphx-update
has non-HTML nodes as children - Fix
phx_trigger_action
submitting the form before the DOM updates are complete
- Fix race condition on
phx-trigger-action
causing reconnects before server form submit
- Optimize DOM prepend and append operations
- Add
Phoenix.LiveView.send_update_after/3
- Fix scroll position when using back/forward with
live_redirect
's - Handle recursive components when generating diffs
- Support hard redirects on mount
- Properly track nested components on deletion on
Phoenix.LiveViewTest
- Fix hidden inputs throwing selection range error
- Support
render_layout
with LiveEEx
- Fix focused inputs being overwritten by latent patch
- Fix LiveView error when
"_target"
input name contains array - Fix change tracking when passing a do-block to components
- Fix Map of assigns together with
@inner_content
causingno function clause matching in Keyword.put/3
error - Fix
LiveViewTest
failing to patch children properly for append/prepend based phx-update's - Fix argument error when providing
:as
option to alive
route - Fix page becoming unresponsive when the server crashes while handling a live patch
- Fix empty diff causing pending data-ref based updates, such as classes and
phx-disable-with
content to not be updated - Fix bug where throttling keydown events would eat key presses
- Fix
<textarea>
's failing to be disabled on form submit - Fix text node DOM memory leak when using
phx-update
append/prepend
- Allow
:router
to be given torender_component
- Display file on compile warning for
~L
- Log error on client when using a hook without a DOM ID
- Optimize
phx-update
append/prepend based DOM updates
- Fix nested
live_render
's failing to be torn down when removed from the DOM in certain cases - Fix LEEx issue for nested conditions failing to be re-evaluated
- Fix IE11 issue where
document.activeElement
creates a null reference - Fix setup and teardown of root views when explicitly calling
liveSocket.disconnect()
followed byliveSocket.connect()
- Fix
error_tag
failing to be displayed for non-text based inputs such as selects and checkboxes as thephx-no-feedback
class was always applied - Fix
phx-error
class being applied onlive_redirect
- Properly handle Elixir's special variables, such as
__MODULE__
- No longer set disconnected class during patch
- Track flash keys to fix back-to-back flashes from being discarded
- Properly handle empty component diffs in the client for cases where the component has already been removed on the server
- Make sure components in nested live views do not conflict
- Fix
phx-static
not being sent from the client for child views - Do not fail when trying to delete a view that was already deleted
- Ensure
beforeDestroy
is called on hooks in children of a removed element
- Allow the whole component static subtree to be shared when the component already exists on the client
- Add telemetry events to
mount
,handle_params
, andhandle_event
- Add
push_event
for pushing events and data from the server to the client - Add client
handleEvent
hook method for receiving events pushed from the server - Add ability to receive a reply to a
pushEvent
from the server via{:reply, map, socket}
- Use event listener for popstate to avoid conflicting with user-defined popstate handlers
- Log error on client when rendering a component with no direct DOM children
- Make
assigns.myself
a struct to catch mistakes - Log if component doesn't exist on
send_update
, raise if module is unavailable
- Fix duplicate debounced events from being triggered on blur with timed debounce
- Fix client error when
live_redirect
ed route results in a redirect to a non-live route on the server - Fix DOM siblings being removed when a rootless component is updated
- Fix debounced input failing to send last change when blurred via Tab, Meta, or other non-printable keys
- Add
dom
option toLiveSocket
withonBeforeElUpdated
callback for external client library support of broad DOM operations
- Fix a bug where swapping a root template with components would cause the LiveView to crash
- Fix forced page refresh when
push_redirect
from alive_redirect
- Optimize component diffs to avoid sending empty diffs
- Optimize components to share static values
- [LiveViewTest] Automatically synchronize before render events
- No longer send event metadata by default. Metadata is now opt-in and user defined at the
LiveSocket
level. To maintain backwards compatibility with pre-0.13 behaviour, you can provide the following metadata option:
let liveSocket = new LiveSocket("/live", Socket, {
params: {_csrf_token: csrfToken},
metadata: {
click: (e, el) => {
return {
altKey: e.altKey,
shiftKey: e.shiftKey,
ctrlKey: e.ctrlKey,
metaKey: e.metaKey,
x: e.x || e.clientX,
y: e.y || e.clientY,
pageX: e.pageX,
pageY: e.pageY,
screenX: e.screenX,
screenY: e.screenY,
offsetX: e.offsetX,
offsetY: e.offsetY,
detail: e.detail || 1,
}
},
keydown: (e, el) => {
return {
altGraphKey: e.altGraphKey,
altKey: e.altKey,
code: e.code,
ctrlKey: e.ctrlKey,
key: e.key,
keyIdentifier: e.keyIdentifier,
keyLocation: e.keyLocation,
location: e.location,
metaKey: e.metaKey,
repeat: e.repeat,
shiftKey: e.shiftKey
}
}
}
})
- Fix error caused by Chrome sending a keydown event on native UI autocomplete without a
key
- Fix server error when a live navigation request issues a redirect
- Fix double window bindings when explicit calls to LiveSocket connect/disconnect/connect
- Add
Phoenix.LiveView.get_connect_info/1
- Add
Phoenix.LiveViewTest.put_connect_info/2
andPhoenix.LiveViewTest.put_connect_params/2
- Add support for tracking static asset changes on the page across cold server deploys
- Add support for passing a
@myself
target to a hook'spushEventTo
target - Add configurable metadata for events with new
metadata
LiveSocket option - Add
"_mounts"
key in connect params which specifies the number of times a LiveView has mounted
- Fix component
innerHTML
being discarded when a sibling DOM element appears above it, in cases where the component lacks a DOM ID - Fix Firefox reconnecting briefly during hard redirects
- Fix
phx-disable-with
and other pending attributes failing to be restored when an empty patch is returned by server - Ensure LiveView module is loaded before mount to prevent first application request logging errors if the very first request is to a connected LiveView
This version of LiveView comes with an overhaul of the testing module, more closely integrating your LiveView template with your LiveView events. For example, in previous versions, you could write this test:
render_click(live_view, "increment_by", %{by: 1})
However, there is no guarantee that there is any element on the page with a phx-click="increment"
attribute and phx-value-by
set to 1. With LiveView 0.12.0, you can now write:
live_view
|> element("#term .buttons a", "Increment")
|> render_click()
The new implementation will check there is a button at #term .buttons a
, with "Increment" as text, validate that it has a phx-click
attribute and automatically submit to it with all relevant phx-value
entries. This brings us closer to integration/acceptance test frameworks without any of the overhead and complexities of running a headless browser.
- Add
assert_patch/3
andassert_patched/2
for asserting on patches - Add
follow_redirect/3
to automatically follow redirects fromrender_*
events - Add
phx-trigger-action
form annotation to trigger an HTTP form submit on next DOM patch
- Fix
phx-target
@myself
targeting a sibling LiveView component with the same component ID - Fix
phx:page-loading-stop
firing before the DOM patch has been performed - Fix
phx-update="prepend"
failing to properly patch the DOM when the same ID is updated back to back - Fix redirects on mount failing to copy flash
-
phx-error-for
has been removed in favor ofphx-feedback-for
.phx-feedback-for
will set aphx-no-feedback
class whenever feedback has to be hidden -
Phoenix.LiveViewTest.children/1
has been renamed toPhoenix.LiveViewTest.live_children/1
-
Phoenix.LiveViewTest.find_child/2
has been renamed toPhoenix.LiveViewTest.find_live_child/2
-
Phoenix.LiveViewTest.assert_redirect/3
no longer matches on the flash, instead it returns the flash -
Phoenix.LiveViewTest.assert_redirect/3
no longer matches on the patch redirects, useassert_patch/3
instead -
Phoenix.LiveViewTest.assert_remove/3
has been removed. If the LiveView crashes, it will cause the test to crash too -
Passing a path with DOM IDs to
render_*
test functions is deprecated. Furthermore, they now require aphx-target="<%= @id %>"
on the given DOM ID:<div id="component-id" phx-target="component-id"> ... </div>
html = render_submit([view, "#component-id"], event, value)
In any case, this API is deprecated and you should migrate to the new element based API.
- Fix readonly states failing to be undone after an empty diff
- Fix dynamically added child failing to be joined by the client
- Fix teardown bug causing stale client sessions to attempt a rejoin on reconnect
- Fix orphaned prepend/append content across joins
- Track
unless
in LiveEEx engine
render_event
/render_click
and friends now expect a DOM ID selector to be given when working with components. For example, instead ofrender_click([live, "user-13"])
, you should writerender_click([live, "#user-13"])
, mirroring thephx-target
API.- Accessing the socket assigns directly
@socket.assigns[...]
in a template will now raise the exceptionPhoenix.LiveView.Socket.AssignsNotInSocket
. The socket assigns are available directly inside the template as LiveEExassigns
, such as@foo
and@bar
. Any assign access should be done using the assigns in the template where proper change tracking takes place.
- Trigger debounced events immediately on input blur
- Support
defaults
option onLiveSocket
constructor to configure defaultphx-debounce
andphx-throttle
values, allowing<input ... phx-debounce>
- Add
detail
key to click event metadata for detecting double/triple clicks
-
Remove
socket.assigns
during render to avoid change tracking bugs. If you were previously relying on passing@socket
to functions then referencing socket assigns, pass the explicit assign instead to your functions from the template. -
Removed
assets/css/live_view.css
. If you want to show a progress bar then inapp.css
, replace- @import "../../../../deps/phoenix_live_view/assets/css/live_view.css"; + @import "../node_modules/nprogress/nprogress.css";
and add
nprogress
toassets/package.json
. Full details in the Progress animation guide
- Fix client issue with greater than two levels of LiveView nesting
- Fix bug causing entire LiveView to be re-rendering with only a component changed
- Fix issue where rejoins would not trigger
phx:page-loading-stop
- Support deep change tracking so
@foo.bar
only executes and diffs when bar changes - Add
@myself
assign, to allow components to target themselves instead of relying on a DOM ID, for example:phx-target="<%= @myself %>"
- Optimize various client rendering scenarios for faster DOM patching of components and append/prepended content
- Add
enableProfiling()
anddisableProfiling()
toLiveSocket
for client performance profiling to aid the development process - Allow LiveViews to be rendered inside LiveComponents
- Add support for clearing flash inside components
- Rename socket assign
@live_view_module
to@live_module
- Rename socket assign
@live_view_action
to@live_action
- LiveView no longer uses the default app layout and
put_live_layout
is no longer supported. Instead, useput_root_layout
. Note, however, that the layout given toput_root_layout
must use@inner_content
instead of<%= render(@view_module, @view_template, assigns) %>
and that the root layout will also be used by regular views. Check the Live Layouts section of the docs.
- Fix loading states causing nested LiveViews to be removed during live navigation
- Only trigger
phx-update="ignore"
hook if data attributes have changed - Fix LiveEEx fingerprint bug causing no diff to be sent in certain cases
- Support collocated templates where an
.html.leex
template of the same basename of the LiveView will be automatically used forrender/1
- Add
live_title_tag/2
helper for automatic prefix/suffix on@page_title
updates
- Do not set ignored inputs and buttons as readonly
- Only decode paths in URIs
- Only destroy main descendents when replacing main
- Fix sibling component patches when siblings at same root DOM tree
- Do not pick the layout from
:use
on child LiveViews - Respect when the layout is set to
false
in the router and on mount - Fix sibling component patch when component siblings lack a container
- Make flash optional (i.e. LiveView will still work if you don't
fetch_flash
before)
- Raise if
:flash
is given as an assign - Support user-defined metadata in router
- Allow the router to be accessed as
socket.router
- Allow
MFArgs
as the:session
option in thelive
router macro - Trigger page loading event when main LV errors
- Automatically clear the flash on live navigation examples - only the newly assigned flash is persisted
- Support
phx-disable-with
on live redirect and live patch links
- Fix focus issue on date and time inputs
- Fix LiveViews failing to mount when page restored from back/forward cache following a
redirect
on the server - Fix IE coercing
undefined
to string when issuing pushState - Fix IE error when focused element is null
- Fix client error when using components and live navigation where a dynamic template is rendered
- Fix latent component diff causing error when component removed from DOM before patch arrives
- Fix race condition where a component event received on the server for a component already removed by the server raised a match error
- Remove
Phoenix.LiveView.Flash
in favor of:fetch_live_flash
imported byPhoenix.LiveView.Router
- Live layout must now access the child contents with
@inner_content
instead of invoking the LiveView directly - Returning
:stop
tuples from LiveViewmount
orhandle_[params|call|cast|info|event]
is no longer supported. LiveViews are stopped when issuing aredirect
orpush_redirect
- Add
put_live_layout
plug to put the root layout used for live routes - Allow
redirect
andpush_redirect
from mount - Use acknowledgement tracking to avoid patching inputs until the server has processed the form event
- Add CSS loading states to all phx bound elements with event specific CSS classes
- Dispatch
phx:page-loading-start
andphx:page-loading-stop
on window for live navigation, initial page loads, and form submits, for user controlled page loading integration - Allow any phx bound element to specify
phx-page-loading
to dispatch loading events above when the event is pushed - Add client side latency simulator with new
enableLatencySim(milliseconds)
anddisableLatencySim()
- Add
enableDebug()
anddisableDebug()
toLiveSocket
for ondemand browser debugging from the web console - Do not connect LiveSocket WebSocket or bind client events unless a LiveView is found on the page
- Add
transport_pid/1
to return the websocket transport pid when the socket is connected
- Fix issue where a failed mount from a
live_redirect
would reload the current URL instead of the attempted new URL
- Fix checkbox bug failing to send
phx-change
event to the server in certain cases - Fix checkbox bug failing to maintain checked state when a checkbox is programmatically updated by the server
- Fix select bug in Firefox causing the highlighted index to jump when a patch is applied during hover state
live_redirect
was removed in favor ofpush_patch
(for updating the URL and params of the current LiveView) andpush_redirect
(for updating the URL to another LiveView)live_link
was removed in favor oflive_patch
(for updating the URL and params of the current LiveView) andlive_redirect
(for updating the URL to another LiveView)Phoenix.LiveViewTest.assert_redirect
no longer accepts an anonymous function in favor of executing the code prior to asserting the redirects, just likeassert_receive
.
- Support
@live_view_action
in LiveViews to simplify tracking of URL state - Recovery form input data automatically on disconnects or crash recovery
- Add
phx-auto-recover
form binding for specialized recovery - Scroll to top of page while respecting anchor hash targets on
live_patch
andlive_redirect
- Add
phx-capture-click
to use event capturing to bind a click event as it propagates inwards from the target - Revamp flash support so it works between static views, live views, and components
- Add
phx-key
binding to scopephx-window-keydown
andphx-window-keyup
events
- Send
phx-value-*
on key events - Trigger
updated
hook callbacks onphx-update="ignore"
container when the container's attributes have changed - Fix nested
phx-update="append"
raising ArgumentError in LiveViewTest - Fix updates not being applied in rare cases where an leex template is wrapped in an if expression
- LiveView
mount/2
has been deprecated in favor ofmount/3
. The params are now passed as the first argument tomount/3
, followed by the session and socket.
- The socket session now accepts only string keys
- Allow window beforeunload to be cancelled without losing websocket connection
- Fix handle_params not decoding URL path parameters properly
- Fix LiveViewTest error when routing at root path
- Fix URI encoded params failing to be decoded in
handle_params
- Fix component target failing to locate correct component when the target is on an input tag
- Fix optimization bug causing some DOM nodes to be removed on updates
- Fix phx-change bug causing phx-target to not be used
LiveView now makes the connection session automatically available in LiveViews. However, to do so, you need to configure your endpoint accordingly, otherwise LiveView will fail to connect.
The steps are:
-
Find
plug Plug.Session, ...
in your endpoint.ex and move the options...
to a module attribute:@session_options [ ... ]
-
Change the
plug Plug.Session
to use said attribute:plug Plug.Session, @session_options
-
Also pass the
@session_options
to your LiveView socket:socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]]
-
You should define the CSRF meta tag inside in your layout, before
app.js
is included:<meta name="csrf-token" content={Plug.CSRFProtection.get_csrf_token()} /> <script type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
-
Then in your app.js:
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content"); let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}});
Also note that the session from now on will have string keys. LiveView will warn if atom keys are used.
- Respect new tab behavior in
live_link
- Add
beforeUpdate
andbeforeDestroy
JS hooks - Make all assigns defined on the socket mount available on the layout on first render
- Provide support for live layouts with new
:layout
option - Detect duplicate IDs on the front-end when DEBUG mode is enabled
- Automatically forward the session to LiveView
- Support "live_socket_id" session key for identifying (and disconnecting) LiveView sockets
- Add support for
hibernate_after
on LiveView processes - Support redirecting to full URLs on
live_redirect
andredirect
- Add
offsetX
andoffsetY
to click event metadata - Allow
live_link
andlive_redirect
to exist anywhere in the page and it will always target the main LiveView (the one defined at the router)
phx-target="window"
has been removed in favor ofphx-window-keydown
,phx-window-focus
, etc, and thephx-target
binding has been repurposed for targeting LiveView and LiveComponent events from the clientPhoenix.LiveView
no longer definedlive_render
andlive_link
. These functions have been moved toPhoenix.LiveView.Helpers
which can now be fully imported in your views. In other words, replaceimport Phoenix.LiveView, only: [live_render: ..., live_link: ...]
byimport Phoenix.LiveView.Helpers
- Fix bug causing blurred inputs
- Add
Phoenix.LiveComponent
to compartmentalize state, markup, and events in LiveView - Handle outdated clients by refreshing the page with jitter when a valid, but outdated session is detected
- Only dispatch live link clicks to router LiveView
- Refresh the page for graceful error recovery on failed mount when the socket is in a connected state
- Fix
phx-hook
destroyed callback failing to be called in certain cases - Fix back/forward bug causing LiveView to fail to remount
live_isolated
in tests no longer requires a router and a pipeline (it now expects only 3 arguments)- Raise if
handle_params
is used on a non-router LiveView
- [LiveViewTest] Fix function clause errors caused by HTML comments
- Add
phx-debounce
andphx-throttle
bindings to rate limit events
- IE11 support now requires two additional polyfills,
mdn-polyfills/CustomEvent
andmdn-polyfills/String.prototype.startsWith
- Fix IE11 support caused by unsupported
getAttributeNames
lookup - Fix Floki dependency compilation warnings
- [LiveView.Router] Fix module concat failing to build correct layout module when using custom namespace
- [LiveViewTest] Fix
phx-update
append/prepend containers not building proper DOM content - [LiveViewTest] Fix
phx-update
append/prepend containers not updating existing child containers with matching IDs
- [LiveView] Add new
:container
option touse Phoenix.LiveView
- [LiveViewTest] Add
live_isolated
test helper for testing LiveViews which are not routable
- Replace
configure_temporary_assigns/2
with 3-tuple mount return, supporting a:temporary_assigns
key - Do not allow
redirect
/live_redirect
on mount nor in child live views - All
phx-update
containers now require a unique ID LiveSocket
JavaScript constructor now requires explicit dependency injection of Phoenix Socket constructor. For example:
import {Socket} from "phoenix"
import LiveSocket from "phoenix_live_view"
let liveSocket = new LiveSocket("/live", Socket, {...})
- Fix
phx-update=append/prepend
failing to join new nested live views or wire up new phx-hooks - Fix number input handling causing some browsers to reset form fields on invalid inputs
- Fix multi-select decoding causing server error
- Fix multi-select change tracking failing to submit an event when a value is deselected
- Fix live redirect loop triggered under certain scenarios
- Fix params failing to update on re-mounts after live_redirect
- Fix blur event metadata being sent with type of
"focus"
phx-value
has no effect, usephx-value-*
instead- The
:path_params
key in session has no effect (usehandle_params
in LiveView instead)
- Use optimized
insertAdjacentHTML
for faster append/prepend and proper CSS animation handling - Allow for replacing previously appended/prepended elements by replacing duplicate IDs during append/prepend instead of adding new DOM nodes
- Fix duplicate append/prepend updates when parent content is updated
- Fix JS hooks not being applied for appending and prepended content
- The LiveView
handle_in/3
callback now receives a map of metadata about the client event - For
phx-change
events,handle_in/3
now receives a"_target"
param representing the keyspace of the form input name which triggered the change - Multiple values may be provided for any phx binding by using the
phx-value-
prefix, such asphx-value-myval1
,phx-value-myval2
, etc - Add control over the DOM patching via
phx-update
, which can be set to"replace"
,"append"
,"prepend"
or"ignore"
phx-ignore
was renamed tophx-update="ignore"