Skip to content

Instantly share code, notes, and snippets.

@ukutaht
Last active September 10, 2025 05:33
Show Gist options
  • Save ukutaht/c296df0b1516d82372cd4f2d83b6a67e to your computer and use it in GitHub Desktop.
Save ukutaht/c296df0b1516d82372cd4f2d83b6a67e to your computer and use it in GitHub Desktop.
Liveview dynamic rendering issue
#!/usr/bin/env elixir
# Minimal Phoenix LiveView single file example
# Run with: elixir minimal_liveview.exs
# Access at: http://localhost:4001
Application.put_env(:minimal_app, MinimalApp.Endpoint,
http: [ip: {127, 0, 0, 1}, port: 4001],
server: true,
live_view: [signing_salt: "aaaaaaaa"],
secret_key_base: String.duplicate("a", 64),
debug_errors: true
)
Mix.install([
{:plug_cowboy, "~> 2.5"},
{:jason, "~> 1.0"},
{:phoenix, "~> 1.7"},
{:phoenix_live_view, "~> 1.0"}
])
defmodule MinimalApp.ErrorHTML do
def render(template, _assigns) do
Phoenix.Controller.status_message_from_template(template)
end
end
defmodule MinimalApp.Layouts do
use Phoenix.Component
def app(assigns) do
~H"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="csrf-token" content={Plug.CSRFProtection.get_csrf_token()} />
<title>Minimal LiveView</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/priv/static/phoenix.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/priv/static/phoenix_live_view.min.js"></script>
<style>
body { font-family: system-ui, sans-serif; margin: 40px; }
.container { max-width: 800px; }
button { padding: 8px 16px; margin: 4px; background: #3b82f6; color: white; border: none; border-radius: 4px; cursor: pointer; }
button:hover { background: #2563eb; }
</style>
</head>
<body>
<div class="container">
<%= @inner_content %>
</div>
<script>
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
let liveSocket = new window.LiveView.LiveSocket("/live", window.Phoenix.Socket, {params: {_csrf_token: csrfToken}})
liveSocket.connect()
</script>
</body>
</html>
"""
end
end
defmodule MinimalApp.Components do
use Phoenix.Component
attr :type, :string, default: nil
attr :class, :string, default: nil
attr :rest, :global, include: ~w(disabled form name value)
slot :inner_block, required: true
def button(assigns) do
~H"""
<button
type={@type}
class={@class}
{@rest}
>
{render_slot(@inner_block)}
</button>
"""
end
attr :class, :string, default: ""
attr :as, :any, default: nil
slot :inner_block, required: true
def dropdown_trigger(assigns) do
assigns[:as].(assigns)
end
end
defmodule MinimalApp.HomeLive do
use Phoenix.LiveView
def mount(_params, _session, socket) do
{:ok, socket}
end
def render(assigns) do
~H"""
<MinimalApp.Components.dropdown_trigger as={&MinimalApp.Components.button/1} />
"""
end
end
defmodule MinimalApp.Router do
use Phoenix.Router
import Phoenix.Controller
import Phoenix.LiveView.Router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
plug :put_root_layout, html: {MinimalApp.Layouts, :app}
plug :protect_from_forgery
end
scope "/", MinimalApp do
pipe_through :browser
live "/", HomeLive
end
end
defmodule MinimalApp.Endpoint do
use Phoenix.Endpoint, otp_app: :minimal_app
@session_options [
store: :cookie,
key: "_minimal_app_key",
signing_salt: "aaaaaaaa"
]
socket "/live", Phoenix.LiveView.Socket,
websocket: [connect_info: [session: @session_options]]
plug Plug.RequestId
plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint]
plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
pass: ["*/*"],
json_decoder: Phoenix.json_library()
plug Plug.MethodOverride
plug Plug.Head
plug Plug.Session, @session_options
plug MinimalApp.Router
end
# Start the application
{:ok, _} = Supervisor.start_link([MinimalApp.Endpoint], strategy: :one_for_one)
IO.puts("\n๐Ÿš€ Minimal Phoenix LiveView started!")
IO.puts("๐Ÿ“ฑ Open http://localhost:4001 in your browser")
IO.puts("๐Ÿ›‘ Press Ctrl+C to stop\n")
Process.sleep(:infinity)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment