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

$curl -o ~/.claude/skills/phoenix-liveview/SKILL.md --create-dirs "https://raw.githubusercontent.com/ratnesh-maurya/cursor-claude-personas/main/senior-elixir-developer/.claude/skills/phoenix-liveview/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/phoenix-liveview/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How phoenix-liveview Compares

Feature / Agentphoenix-liveviewStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/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 LiveView

Related Skills

wordpress-penetration-testing

5
from ratnesh-maurya/cursor-claude-personas

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

5
from ratnesh-maurya/cursor-claude-personas

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

5
from ratnesh-maurya/cursor-claude-personas

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

5
from ratnesh-maurya/cursor-claude-personas

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

5
from ratnesh-maurya/cursor-claude-personas

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

5
from ratnesh-maurya/cursor-claude-personas

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

5
from ratnesh-maurya/cursor-claude-personas

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

5
from ratnesh-maurya/cursor-claude-personas

Centralized 'Truth Engine' for cross-jurisdictional legal context (US, EU, CA) and contract scaffolding.

amazon-alexa

5
from ratnesh-maurya/cursor-claude-personas

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

5
from ratnesh-maurya/cursor-claude-personas

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

5
from ratnesh-maurya/cursor-claude-personas

Teaches agents to iteratively build websites using Stitch with an autonomous baton-passing loop pattern

product-design

5
from ratnesh-maurya/cursor-claude-personas

Design de produto nivel Apple — sistemas visuais, UX flows, acessibilidade, linguagem visual proprietaria, design tokens, prototipagem e handoff. Cobre Figma, design systems, tipografia, cor,...