phoenix-liveview
Phoenix LiveView patterns for real-time web apps: components, streams, hooks, PubSub, Presence. Use when building interactive server-rendered UIs with Phoenix.
Best use case
phoenix-liveview is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Phoenix LiveView patterns for real-time web apps: components, streams, hooks, PubSub, Presence. Use when building interactive server-rendered UIs with Phoenix.
Teams using phoenix-liveview should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/phoenix-liveview/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How phoenix-liveview Compares
| Feature / Agent | phoenix-liveview | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Phoenix LiveView patterns for real-time web apps: components, streams, hooks, PubSub, Presence. Use when building interactive server-rendered UIs with Phoenix.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Phoenix LiveView
Real-time, server-rendered interactive web applications with Phoenix LiveView.
## When to Use
- Building real-time interactive UIs without client-side JavaScript frameworks
- Server-rendered pages that need dynamic updates (forms, dashboards, chat)
- Implementing collaborative features with PubSub/Presence
- Progressive enhancement on top of server-rendered HTML
## Do Not Use When
- Offline-first applications requiring full client-side state
- Heavy client-side computation (video editing, complex animations)
- Static content sites with no interactivity
## Architecture
```
[Browser] ←──WebSocket──→ [LiveView Process (1 per client)]
├── State (assigns)
├── HEEx Template (render)
└── Event Handlers
```
- Initial render: full server-side HTML (SEO-friendly)
- Subsequent updates: only diffs sent over WebSocket (5-10x smaller)
- Each connected client spawns a lightweight BEAM process
## Function Components vs LiveComponents
**Prefer function components** (stateless) for most UI:
```elixir
# Function component — stateless, pure
attr :name, :string, required: true
attr :class, :string, default: ""
def greeting(assigns) do
~H"""
<div class={@class}>Hello, {@name}!</div>
"""
end
```
**Use LiveComponents** only when you need isolated state:
```elixir
defmodule MyAppWeb.SearchBox do
use MyAppWeb, :live_component
def mount(socket), do: {:ok, assign(socket, query: "", results: [])}
def handle_event("search", %{"query" => query}, socket) do
results = MyApp.Search.run(query)
{:noreply, assign(socket, query: query, results: results)}
end
def render(assigns) do
~H"""
<form phx-submit="search" phx-target={@myself}>
<input name="query" value={@query} phx-debounce="300" />
<div :for={result <- @results}>{result.title}</div>
</form>
"""
end
end
```
## Streams (Large Lists)
Never store large collections in assigns. Use streams:
```elixir
def mount(_params, _session, socket) do
{:ok, stream(socket, :messages, Messages.list_recent())}
end
def handle_info({:new_message, message}, socket) do
{:noreply, stream_insert(socket, :messages, message, at: -1)}
end
def handle_info({:delete_message, message}, socket) do
{:noreply, stream_delete(socket, :messages, message)}
end
```
In template:
```heex
<div id="messages" phx-update="stream">
<div :for={{dom_id, message} <- @streams.messages} id={dom_id}>
{message.body}
</div>
</div>
```
## Async Operations
```elixir
# assign_async — for data loading
def mount(_params, _session, socket) do
{:ok, assign_async(socket, :user_stats, fn -> {:ok, %{user_stats: fetch_stats()}} end)}
end
# In template
<.async_result :let={stats} assign={@user_stats}>
<:loading>Loading...</:loading>
<:failed :let={_reason}>Failed to load</:failed>
{stats.total_users} users
</.async_result>
```
## PubSub for Real-Time
```elixir
# Subscribe in mount
def mount(%{"room_id" => room_id}, _session, socket) do
if connected?(socket) do
Phoenix.PubSub.subscribe(MyApp.PubSub, "room:#{room_id}")
end
{:ok, assign(socket, room_id: room_id)}
end
# Handle broadcasts
def handle_info({:new_message, message}, socket) do
{:noreply, stream_insert(socket, :messages, message)}
end
# Broadcast from context
def create_message(attrs) do
case Repo.insert(Message.changeset(%Message{}, attrs)) do
{:ok, message} ->
Phoenix.PubSub.broadcast(MyApp.PubSub, "room:#{message.room_id}", {:new_message, message})
{:ok, message}
error -> error
end
end
```
## JavaScript Hooks
```elixir
# In template
<div id="chart" phx-hook="Chart" data-points={Jason.encode!(@points)}></div>
```
```javascript
// In app.js
let Hooks = {}
Hooks.Chart = {
mounted() {
this.renderChart(JSON.parse(this.el.dataset.points))
},
updated() {
this.renderChart(JSON.parse(this.el.dataset.points))
},
renderChart(points) { /* D3/Chart.js rendering */ }
}
let liveSocket = new LiveSocket("/live", Socket, {hooks: Hooks})
```
Push events from hooks:
```javascript
this.pushEvent("chart_clicked", {point_id: id})
```
## Navigation
```elixir
# Patch (same LiveView, update params)
<.link patch={~p"/users?#{[page: @page + 1]}"}>Next</.link>
# Navigate (different LiveView)
<.link navigate={~p"/settings"}>Settings</.link>
# Handle in LiveView
def handle_params(%{"page" => page}, _uri, socket) do
{:noreply, assign(socket, page: String.to_integer(page))}
end
```
## Form Handling
```elixir
def mount(_params, _session, socket) do
changeset = Accounts.change_user(%User{})
{:ok, assign(socket, form: to_form(changeset))}
end
def handle_event("validate", %{"user" => params}, socket) do
changeset = Accounts.change_user(%User{}, params) |> Map.put(:action, :validate)
{:noreply, assign(socket, form: to_form(changeset))}
end
def handle_event("save", %{"user" => params}, socket) do
case Accounts.create_user(params) do
{:ok, _user} -> {:noreply, push_navigate(socket, to: ~p"/users")}
{:error, changeset} -> {:noreply, assign(socket, form: to_form(changeset))}
end
end
```
## Anti-Patterns
- **Storing large lists in assigns**: Use streams for any collection that grows
- **Blocking in mount/3**: Use `connected?/1` to defer expensive work; use `assign_async` for slow data
- **Too many LiveComponents**: Each has lifecycle overhead — prefer function components
- **Not subscribing in mount**: Always subscribe to PubSub in `mount/3` (handles cleanup on disconnect)
- **Missing `phx-debounce`**: Add debounce to text inputs to avoid excessive server roundtrips
## Key Libraries
- `Phoenix.LiveView` (1.1+), `Phoenix.Component`, `Phoenix.PubSub`, `Phoenix.Presence`
- `Flop` / `Flop.Phoenix` — declarative filtering, sorting, pagination
- `LiveSvelte`, `LiveVue` — embed JS framework components inside LiveViewRelated Skills
wordpress-penetration-testing
This skill should be used when the user asks to "pentest WordPress sites", "scan WordPress for vulnerabilities", "enumerate WordPress users, themes, or plugins", "exploit WordPress vu...
php-pro
Write idiomatic PHP code with generators, iterators, SPL data structures, and modern OOP features. Use PROACTIVELY for high-performance PHP applications.
moodle-external-api-development
Create custom external web service APIs for Moodle LMS. Use when implementing web services for course management, user tracking, quiz operations, or custom plugin functionality. Covers parameter va...
laravel-expert
Senior Laravel Engineer role for production-grade, maintainable, and idiomatic Laravel solutions. Focuses on clean architecture, security, performance, and modern standards (Laravel 10/11+).
voice-ai-engine-development
Build real-time conversational AI voice engines using async worker pipelines, streaming transcription, LLM agents, and TTS synthesis with interrupt handling and multi-provider support
voice-ai-development
Expert in building voice AI applications - from real-time voice agents to voice-enabled apps. Covers OpenAI Realtime API, Vapi for voice agents, Deepgram for transcription, ElevenLabs for synthesis...
voice-agents
Voice agents represent the frontier of AI interaction - humans speaking naturally with AI systems. The challenge isn't just speech recognition and synthesis, it's achieving natural conversation flo...
lex
Centralized 'Truth Engine' for cross-jurisdictional legal context (US, EU, CA) and contract scaffolding.
amazon-alexa
Integracao completa com Amazon Alexa para criar skills de voz inteligentes, transformar Alexa em assistente com Claude como cerebro (projeto Auri) e integrar com AWS ecosystem (Lambda, DynamoDB,...
wcag-audit-patterns
Conduct WCAG 2.2 accessibility audits with automated testing, manual verification, and remediation guidance. Use when auditing websites for accessibility, fixing WCAG violations, or implementing ac...
stitch-loop
Teaches agents to iteratively build websites using Stitch with an autonomous baton-passing loop pattern
product-design
Design de produto nivel Apple — sistemas visuais, UX flows, acessibilidade, linguagem visual proprietaria, design tokens, prototipagem e handoff. Cobre Figma, design systems, tipografia, cor,...