
Phoenix Liveview
- 305 installs
- 63 repo stars
- Updated July 18, 2026
- bobmatnyc/claude-mpm-skills
phoenix-liveview is an Elixir development skill that builds interactive Phoenix LiveView UIs with forms, streams, components, and minimal JavaScript for developers who want realtime dashboards and admin tools without a s
About
phoenix-liveview is a claude-mpm-skills guide for building interactive Phoenix LiveView interfaces in Elixir applications. The skill covers forms, streams, components, and minimal JavaScript patterns for realtime dashboards, admin tools, and dynamic server-rendered pages that avoid maintaining a separate single-page application. Developers reach for phoenix-liveview when shipping internal tools, ops dashboards, or customer admin panels that need live updates over WebSockets with Phoenix conventions. It suits teams standardizing on Elixir/Phoenix rather than React or Vue frontends for interactive surfaces.
- LiveView lifecycle and assign management
- HEEx components and function components
- Live streams for large collections
- Form validation and phx-change/submit flows
- JS hooks only where DOM APIs are required
Phoenix Liveview by the numbers
- 305 all-time installs (skills.sh)
- Ranked #754 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 1, 2026 (Skillselion catalog sync)
npx skills add https://github.com/bobmatnyc/claude-mpm-skills --skill phoenix-liveviewAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 305 |
|---|---|
| repo stars | ★ 63 |
| Last updated | July 18, 2026 |
| Repository | bobmatnyc/claude-mpm-skills ↗ |
How do you build realtime UIs with Phoenix LiveView?
Build interactive Phoenix LiveView UIs with forms, streams, components, and minimal JS for dashboards, admin tools, and realtime pages without a separate SPA.
Who is it for?
Elixir developers building admin dashboards, internal tools, or realtime pages who want server-rendered interactivity without a JavaScript SPA.
Skip if: Developers building mobile-native apps or React SPAs who will not use Phoenix LiveView on the server.
When should I use this skill?
User asks to build Phoenix LiveView UI, realtime Elixir dashboards, LiveView forms, streams, or admin tools with minimal JS.
What you get
Phoenix LiveView modules with forms, streams, components, and WebSocket-driven realtime pages without a separate SPA.
- LiveView modules
- realtime dashboard pages
- reusable LiveView components
Files
Phoenix + LiveView (Elixir/BEAM)
Phoenix builds on Elixir and the BEAM VM to deliver fault-tolerant, real-time web applications with minimal JavaScript. LiveView keeps UI state on the server while streaming HTML diffs over WebSockets. The BEAM provides lightweight processes, supervision trees, hot code upgrades, and soft-realtime scheduling.
Key ideas
- OTP supervision keeps web, data, and background processes isolated and restartable.
- Contexts encode domain boundaries (e.g., Accounts, Billing) around Ecto schemas and queries.
- LiveView renders HTML on the server, syncing UI state over WebSockets with minimal client code.
- PubSub + Presence enable fan-out updates, tracking, and collaboration features.
---
Environment and Project Setup
# Erlang + Elixir via asdf (recommended)
asdf install erlang 27.0
asdf install elixir 1.17.3
asdf global erlang 27.0 elixir 1.17.3
# Install Phoenix generator
mix archive.install hex phx_new
# Create project with LiveView + Ecto + esbuild
mix phx.new my_app --live
cd my_app
mix deps.get
mix ecto.create
mix phx.serverProject layout (key pieces):
lib/my_app/application.ex— OTP supervision tree (Repo, Endpoint, Telemetry, PubSub, Oban, etc.)lib/my_app_web/endpoint.ex— Endpoint, plugs, sockets, LiveView configlib/my_app_web/router.ex— Pipelines, scopes, routes, LiveSessionslib/my_app/— Contexts (domain modules) and Ecto schemastest/support/{conn_case,data_case}.ex— Testing helpers for Ecto + Phoenix
---
BEAM + OTP Essentials
Supervision tree (application.ex): keep short, isolated children.
def start(_type, _args) do
children = [
MyApp.Repo,
{Phoenix.PubSub, name: MyApp.PubSub},
MyAppWeb.Endpoint,
{Oban, Application.fetch_env!(:my_app, Oban)},
MyApp.Metrics
]
Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)
endGenServer pattern: wrap stateful services.
defmodule MyApp.Counter do
use GenServer
def start_link(initial \\ 0), do: GenServer.start_link(__MODULE__, initial, name: __MODULE__)
def increment(), do: GenServer.call(__MODULE__, :inc)
@impl true
def handle_call(:inc, _from, state) do
new_state = state + 1
{:reply, new_state, new_state}
end
endBEAM principles
- Prefer many small processes; processes are cheap and isolated.
- Supervise everything with clear restart strategies.
- Use message passing (
GenServer.cast/send) to avoid shared state. - Use ETS/Cachex for in-memory caches; keep them supervised.
---
Phoenix Anatomy and Routing
Pipelines and scopes (router.ex): keep browser/api concerns separated.
defmodule MyAppWeb.Router do
use MyAppWeb, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug :fetch_current_user
end
pipeline :api do
plug :accepts, ["json"]
end
scope "/", MyAppWeb do
pipe_through :browser
live "/", HomeLive
resources "/users", UserController
end
scope "/api", MyAppWeb do
pipe_through :api
resources "/users", Api.UserController, except: [:new, :edit]
end
endPlugs: composable request middleware. Keep plugs pure and short; prefer pipeline plugs over controller plugs when cross-cutting.
---
Contexts and Ecto
Schema + changeset
defmodule MyApp.Accounts.User do
use Ecto.Schema
import Ecto.Changeset
schema "users" do
field :email, :string
field :hashed_password, :string
field :confirmed_at, :naive_datetime
timestamps()
end
def registration_changeset(user, attrs) do
user
|> cast(attrs, [:email, :password])
|> validate_required([:email, :password])
|> validate_format(:email, ~r/@/)
|> validate_length(:password, min: 12)
|> unique_constraint(:email)
|> put_password_hash()
end
defp put_password_hash(%{valid?: true} = changeset),
do: put_change(changeset, :hashed_password, Argon2.hash_pwd_salt(get_change(changeset, :password)))
defp put_password_hash(changeset), do: changeset
endContext API
defmodule MyApp.Accounts do
import Ecto.Query, warn: false
alias MyApp.{Repo, Accounts.User}
def list_users, do: Repo.all(User)
def get_user!(id), do: Repo.get!(User, id)
def register_user(attrs) do
%User{}
|> User.registration_changeset(attrs)
|> Repo.insert()
end
endTransactions with Ecto.Multi
alias Ecto.Multi
def register_and_welcome(attrs) do
Multi.new()
|> Multi.insert(:user, User.registration_changeset(%User{}, attrs))
|> Multi.run(:welcome_email, fn _repo, %{user: user} ->
MyApp.Mailer.deliver_welcome(user)
{:ok, :sent}
end)
|> Repo.transaction()
end---
LiveView Patterns
LiveView module (stateful UI on server)
defmodule MyAppWeb.CounterLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
{:ok, assign(socket, count: 0)}
end
def handle_event("inc", _params, socket) do
{:noreply, update(socket, :count, &(&1 + 1))}
end
def render(assigns) do
~H"""
<div class="space-y-4">
<p class="text-lg">Count: <%= @count %></p>
<button phx-click="inc" class="btn">Increment</button>
</div>
"""
end
endHEEx tips
- Prefer
assign_new/3to lazily compute expensive data only once per connected session. - Use
stream/3for large lists to minimize diff payloads. - Handle params in
handle_params/3for URL-driven state; avoid storing socket state in params.
Live Components
defmodule MyAppWeb.NavComponent do
use MyAppWeb, :live_component
def render(assigns) do
~H"""
<nav>
<%= for item <- @items do %>
<.link navigate={item.href}><%= item.label %></.link>
<% end %>
</nav>
"""
end
endPubSub-driven LiveView
@impl true
def mount(_params, _session, socket) do
if connected?(socket), do: Phoenix.PubSub.subscribe(MyApp.PubSub, "orders")
{:ok, assign(socket, orders: [])}
end
@impl true
def handle_info({:order_created, order}, socket) do
{:noreply, update(socket, :orders, fn orders -> [order | orders] end)}
end---
PubSub, Channels, and Presence
Broadcast changes from contexts
def create_order(attrs) do
with {:ok, order} <- %Order{} |> Order.changeset(attrs) |> Repo.insert() do
Phoenix.PubSub.broadcast(MyApp.PubSub, "orders", {:order_created, order})
{:ok, order}
end
endPresence for online/typing indicators
defmodule MyAppWeb.RoomChannel do
use Phoenix.Channel
alias Phoenix.Presence
def join("room:" <> room_id, _payload, socket) do
send(self(), :after_join)
{:ok, assign(socket, :room_id, room_id)}
end
def handle_info(:after_join, socket) do
Presence.track(socket, socket.assigns.user_id, %{online_at: System.system_time(:second)})
push(socket, "presence_state", Presence.list(socket))
{:noreply, socket}
end
endSecurity: authorize topics in join/3, verify user tokens in params/session, and limit payload size.
---
Testing Phoenix + LiveView
Use mix test with the generated helpers.
# test/support/conn_case.ex
use MyAppWeb.ConnCase, async: true
test "renders home", %{conn: conn} do
conn = get(conn, "/")
assert html_response(conn, 200) =~ "Welcome"
end# LiveView test
use MyAppWeb.ConnCase, async: true
import Phoenix.LiveViewTest
test "counter increments", %{conn: conn} do
{:ok, view, _html} = live(conn, "/counter")
view |> element("button", "Increment") |> render_click()
assert render(view) =~ "Count: 1"
endDataCase: provide sandboxed DB connections; wrap tests in transactions to isolate data.
Fixtures: build factories with ExMachina or simple helper modules under test/support/fixtures.
---
Performance, Ops, and Deployment
- Telemetry: Phoenix exposes events (
[:phoenix, :endpoint, ...]). Export via:telemetry_poller,OpentelemetryPhoenix, andOpentelemetryEcto. - Assets:
mix assets.deployruns npm install, esbuild, tailwind (if configured), and digests. - Releases:
MIX_ENV=prod mix release. Configure runtime env inconfig/runtime.exs. Start withPHX_SERVER=true _build/prod/rel/my_app/bin/my_app start. - Clustering: add
libclusterwith DNS/epmd strategy for horizontal scale; use distributed PubSub/Presence. - Caching: use ETS/Cachex for hot paths; prefer short TTLs and invalidate on write.
- Background jobs: Oban for retries/backoff; supervise it in application tree.
- Hot path checks: enable
:telemetrymetrics, check LiveView diff sizes, avoid large assigns; prefer streams.
---
Common Pitfalls
- Forgetting to subscribe LiveViews to PubSub after
connected?/1check — events will be missed on initial render. - Doing heavy work inside LiveView render; move to contexts and precompute assigns.
- Not using
Ecto.Multifor multi-step writes; failures leave partial state. - Blocking BEAM schedulers with long NIFs or heavy CPU work; offload to ports/Oban jobs.
- Overusing global ETS without supervision or limits; leak memory.
---
Reference Commands
mix phx.routes— list routes and LiveView paths.mix phx.gen.live Accounts User users email:string confirmed_at:naive_datetime— generate LiveView CRUD (review context boundaries afterward).mix format && mix credo --strict— formatting and linting.mix test --seed 0 --max-failures 1— deterministic failures; pair withmix test.watch.
Phoenix + LiveView excels when domain logic stays in contexts, LiveViews stay thin, and the BEAM supervises every component for resilience.
{
"name": "phoenix-liveview",
"version": "1.0.0",
"category": "toolchain",
"toolchain": "elixir",
"framework": "phoenix-liveview",
"tags": [
"elixir",
"phoenix",
"liveview",
"beam",
"otp",
"ecto",
"pubsub",
"presence",
"telemetry"
],
"entry_point_tokens": 180,
"full_tokens": 2842,
"author": "Claude MPM Team",
"license": "MIT",
"requires": [],
"updated": "2025-12-05",
"source_path": "toolchains/elixir/frameworks/phoenix-liveview/SKILL.md",
"repository": "https://github.com/bobmatnyc/claude-mpm-skills"
}
Related skills
FAQ
What UI patterns does phoenix-liveview cover?
phoenix-liveview covers forms, streams, components, and minimal JavaScript for interactive realtime pages such as dashboards and admin tools rendered over Phoenix WebSockets.
When is phoenix-liveview preferable to a React SPA?
phoenix-liveview fits Elixir teams shipping internal tools or admin panels that need live updates without maintaining a separate JavaScript SPA frontend codebase.