View Source Welcome

Welcome to Phoenix LiveView documentation. Phoenix LiveView enables rich, real-time user experiences with server-rendered HTML. A general overview of LiveView and its benefits is available in our README.

What is a LiveView?

LiveViews are processes that receive events, update their state, and render updates to a page as diffs.

The LiveView programming model is declarative: instead of saying "once event X happens, change Y on the page", events in LiveView are regular messages which may cause changes to the state. Once the state changes, the LiveView will re-render the relevant parts of its HTML template and push it to the browser, which updates the page in the most efficient manner.

LiveView state is nothing more than functional and immutable Elixir data structures. The events are either internal application messages (usually emitted by Phoenix.PubSub) or sent by the client/browser.

Every LiveView is first rendered statically as part of a regular HTTP request, which provides quick times for "First Meaningful Paint", in addition to helping search and indexing engines. A persistent connection is then established between the client and server. This allows LiveView applications to react faster to user events as there is less work to be done and less data to be sent compared to stateless requests that have to authenticate, decode, load, and encode data on every request.

Example

LiveView is included by default in Phoenix applications. Therefore, to use LiveView, you must have already installed Phoenix and created your first application. If you haven't done so, check Phoenix' installation guide to get started.

The behaviour of a LiveView is outlined by a module which implements a series of functions as callbacks. Let's see an example. Write the file below to lib/my_app_web/live/thermostat_live.ex:

defmodule MyAppWeb.ThermostatLive do
  use MyAppWeb, :live_view

  def render(assigns) do
    ~H"""
    Current temperature: {@temperature}°F
    <button phx-click="inc_temperature">+</button>
    """
  end

  def mount(_params, _session, socket) do
    temperature = 70 # Let's assume a fixed temperature for now
    {:ok, assign(socket, :temperature, temperature)}
  end

  def handle_event("inc_temperature", _params, socket) do
    {:noreply, update(socket, :temperature, &(&1 + 1))}
  end
end

The module above defines three functions (they are callbacks required by LiveView). The first one is render/1, which receives the socket assigns and is responsible for returning the content to be rendered on the page. We use the ~H sigil to define a HEEx template, which stands for HTML+EEx. They are an extension of Elixir's builtin EEx templates, with support for HTML validation, syntax-based components, smart change tracking, and more. You can learn more about the template syntax in Phoenix.Component.sigil_H/2 (note Phoenix.Component is automatically imported when you use Phoenix.LiveView).

The data used on rendering comes from the mount callback. The mount callback is invoked when the LiveView starts. In it, you can access the request parameters, read information stored in the session (typically information which identifies who is the current user), and a socket. The socket is where we keep all state, including assigns. mount proceeds to assign a default temperature to the socket. Because Elixir data structures are immutable, LiveView APIs often receive the socket and return an updated socket. Then we return {:ok, socket} to signal that we were able to mount the LiveView successfully. After mount, LiveView will render the page with the values from assigns and send it to the client.

If you look at the HTML rendered, you will notice there is a button with a phx-click attribute. When the button is clicked, a "inc_temperature" event is sent to the server, which is matched and handled by the handle_event callback. This callback updates the socket and returns {:noreply, socket} with the updated socket. handle_* callbacks in LiveView (and in Elixir in general) are invoked based on some action, in this case, the user clicking a button. The {:noreply, socket} return means there is no additional replies sent to the browser, only that a new version of the page is rendered. LiveView then computes diffs and sends them to the client.

Now we are ready to render our LiveView. You can serve the LiveView directly from your router:

defmodule MyAppWeb.Router do
  use MyAppWeb, :router

  pipeline :browser do
    ...
  end

  scope "/", MyAppWeb do
    pipe_through :browser
    ...

    live "/thermostat", ThermostatLive
  end
end

Once the LiveView is rendered, a regular HTML response is sent. In your app.js file, you should find the following:

import {Socket} from "phoenix"
import {LiveSocket} from "phoenix_live_view"

let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}})
liveSocket.connect()

Now the JavaScript client will connect over WebSockets and mount/3 will be invoked inside a spawned LiveView process.

Parameters and session

The mount callback receives three arguments: the request parameters, the session, and the socket.

The parameters can be used to read information from the URL. For example, assuming you have a Thermostat module defined somewhere that can read this information based on the house name, you could write this:

def mount(%{"house" => house}, _session, socket) do
  temperature = Thermostat.get_house_reading(house)
  {:ok, assign(socket, :temperature, temperature)}
end

And then in your router:

live "/thermostat/:house", ThermostatLive

The session retrieves information from a signed (or encrypted) cookie. This is where you can store authentication information, such as current_user_id:

def mount(_params, %{"current_user_id" => user_id}, socket) do
  temperature = Thermostat.get_user_reading(user_id)
  {:ok, assign(socket, :temperature, temperature)}
end

Phoenix comes with built-in authentication generators. See mix phx.gen.auth.

Most times, in practice, you will use both:

def mount(%{"house" => house}, %{"current_user_id" => user_id}, socket) do
  temperature = Thermostat.get_house_reading(user_id, house)
  {:ok, assign(socket, :temperature, temperature)}
end

In other words, you want to read the information about a given house, as long as the user has access to it.

Bindings

Phoenix supports DOM element bindings for client-server interaction. For example, to react to a click on a button, you would render the element:

<button phx-click="inc_temperature">+</button>

Then on the server, all LiveView bindings are handled with the handle_event/3 callback, for example:

def handle_event("inc_temperature", _value, socket) do
  {:noreply, update(socket, :temperature, &(&1 + 1))}
end

To update UI state, for example, to open and close dropdowns, switch tabs, etc, LiveView also supports JS commands (Phoenix.LiveView.JS), which execute directly on the client without reaching the server. To learn more, see our bindings page for a complete list of all LiveView bindings as well as our JavaScript interoperability guide.

LiveView has built-in support for forms, including uploads and association management. See Phoenix.Component.form/1 as a starting point and Phoenix.Component.inputs_for/1 for working with associations. The Uploads and Form bindings guides provide more information about advanced features.

LiveView provides functionality to allow page navigation using the browser's pushState API. With live navigation, the page is updated without a full page reload.

You can either patch the current LiveView, updating its URL, or navigate to a new LiveView. You can learn more about them in the Live Navigation guide.

Generators

Phoenix v1.6 and later includes code generators for LiveView. If you want to see an example of how to structure your application, from the database all the way up to LiveViews, run the following:

$ mix phx.gen.live Blog Post posts title:string body:text

For more information, run mix help phx.gen.live.

For authentication, with built-in LiveView support, run mix phx.gen.auth Account User users.

Compartmentalize state, markup, and events in LiveView

LiveView supports two extension mechanisms: function components, provided by HEEx templates, and stateful components, known as LiveComponents.

Similar to render(assigns) in our LiveView, a function component is any function that receives an assigns map and returns a ~H template. For example:

def weather_greeting(assigns) do
  ~H"""
  <div title="My div" class={@class}>
    <p>Hello {@name}</p>
    <MyApp.Weather.city name="Kraków"/>
  </div>
  """
end

You can learn more about function components in the Phoenix.Component module. At the end of the day, they are a useful mechanism to reuse markup in your LiveViews.

However, sometimes you need to compartmentalize or reuse more than just markup. Perhaps you want to move part of the state or some of the events in your LiveView to a separate module. For these cases, LiveView provides Phoenix.LiveComponent, which are rendered using live_component/1:

<.live_component module={UserComponent} id={user.id} user={user} />

LiveComponents have their own mount/1 and handle_event/3 callbacks, as well as their own state with change tracking support, similar to LiveViews. They are lightweight since they "run" in the same process as the parent LiveView. However, this means an error in a LiveComponent would cause the whole view to fail to render. For a complete rundown, see Phoenix.LiveComponent.

Finally, if you want complete isolation between parts of a LiveView, you can always render a LiveView inside another LiveView by calling live_render/3. This child LiveView runs in a separate process than the parent, with its own callbacks. If a child LiveView crashes, it won't affect the parent. If the parent crashes, all children are terminated.

When rendering a child LiveView, the :id option is required to uniquely identify the child. A child LiveView will only ever be rendered and mounted a single time, provided its ID remains unchanged. To force a child to re-mount with new session data, a new ID must be provided.

Given that it runs in its own process, a nested LiveView is an excellent tool for creating completely isolated UI elements, but it is a slightly expensive abstraction if all you want is to compartmentalize markup or events (or both).

To sum it up:

Guides

This documentation is split into two categories. We have the API reference for all LiveView modules, that's where you will learn more about Phoenix.Component, Phoenix.LiveView, and so on.

LiveView also has many guides to help you on your journey, split on server-side and client-side:

Server-side

These guides focus on server-side functionality:

Client-side

These guides focus on LiveView bindings and client-side integration: