# Easy Phoenix Playground Restarts in LiveBook ```elixir Mix.install([ {:phoenix_playground, ">= 0.0.0"} ]) ``` ## The Problem Phoenix Playground is a great tool for quickly demonstrating and testing small bits of Phoenix Code. LiveBook is a great tool for sharing and easily running Elixir code from the browser. But when you run a playground in LiveBook there's no easy way to stop it and start another one with different code. Our goal in this post is to come up with a simple solution that will let us easily run multiple Phoenix examples in a row in a single LiveBook. ## The Solution PlaygroundManager, a super simple module with a helper function to stop the current playground if it's running, and a helper function that will automatically stop the current playground and start a new one with the given options. ```elixir defmodule PlaygroundManager do @moduledoc """ A wrapper around PhoenixPlayground that makes it more LiveBook friendly. """ def start(opts) do stop() PhoenixPlayground.start(opts) end def stop do case Supervisor.which_children(PhoenixPlayground.Application) do [{PhoenixPlayground, pid, _, _} | _] when is_pid(pid) -> Supervisor.terminate_child(PhoenixPlayground.Application, PhoenixPlayground) Supervisor.delete_child(PhoenixPlayground.Application, PhoenixPlayground) :ok _ -> {:error, :not_running} end end end ``` Now let's try it out with some LiveViews. ```elixir defmodule DemoLive do use Phoenix.LiveView def render(assigns) do ~H"""
Welcome to DemoLive!!!
""" end def mount(_params, _session, socket) do {:ok, socket} end end PlaygroundManager.start(live: DemoLive) ``` Executing that block of code should start the playground and automatically open a new tab showing the DemoLiveView. Now let's define another simple counter LiveView and try launching that with PlaygroundManager. ```elixir defmodule CounterLive do use Phoenix.LiveView def render(assigns) do ~H"""
The current count is: <%= @count %>
""" end def mount(_params, _session, socket) do {:ok, assign(socket, count: 0)} end def handle_event("update-count", %{"count" => count}, socket) do {:noreply, assign(socket, count: String.to_integer(count))} end end PlaygroundManager.start(live: CounterLive) ``` Running that block should launch a new tab showing the counter LiveView. ## Putting them together Both of our LiveView modules are still defined, which means we can easily use them again in a new example. For example, let's define a simple Router that will let us visit both. ```elixir defmodule DemoRouter do use Phoenix.Router import Phoenix.LiveView.Router pipeline :browser do plug :accepts, ["html"] end scope "/" do pipe_through :browser live "/counter", CounterLive live "/", DemoLive end end PlaygroundManager.start(plug: DemoRouter) ``` Now you can visit the counter LiveView at [`/counter`](http://localhost:4000/counter) and the DemoLiveView at [`/`](http://localhost:4000/). ## Conclusion This super simple module makes it much easier to demonstrate multiple Phoenix concepts in a single LiveBook. You can use this immediately by simply including the module in the setup of your LiveBook, you could even forgo the module and just define anonymous functions but I think the module is probably nicer. Hopefully in the future some of this functionality will be included in Phoenix Playground itself. ### Suggestions - Set a `port` variable early in the Livebook to avoid conflicts with other Phoenix apps that the reader of your LiveBook might have running. - Set an `open_browser?` variable early in the Livebook to let readers opt out of launching a new tab for each example. ## Source - [Easy Phoenix Playground Restarts in LiveBook](https://jakeprem.com/posts/easy-livebook-phoenix-playground-restarts/) - Author: Jake Prem - Published: 2025-03-02