In Phoenix, controller actions usually render templates wrapped in a layout β like app.html.heex
. But sometimes, especially for API endpoints or standalone HTML fragments, you want no layout at all.
Hereβs how to render a controller action without any layout, including the root layout introduced in Phoenix 1.6+.
The problem
You define a route like this:
scope "/api", MyAppWeb do
pipe_through :browser
get "/my-endpoint", ApiController, :my_endpoint
end
And in your controller:
def my_endpoint(conn, _params) do
conn
|> put_layout(false)
|> render("my_endpoint.html")
end
But the template still renders inside the root layout (e.g., app.html.heex
). Why?
The fix
Phoenix now separates the root layout from the view layout. To disable both, do this:
def my_endpoint(conn, _params) do
conn
|> put_root_layout(false) # disables the outer layout (Phoenix 1.6+)
|> put_layout(false) # disables the controller/view layout
|> render("my_endpoint.html")
end
Now your template renders as-is, without any wrapping HTML.
Bonus tips
-
Returning JSON or plain text? Just use
json/2
ortext/2
β no layout applies:def dkk_calendar(conn, _params) do json(conn, %{events: []}) end
-
Serving an
.ics
file or static content? Useput_resp_content_type/2
andsend_resp/3
directly. -
Prefer
pipe_through :api
for endpoints like/api/dkk-calendar
, unless you need session or CSRF protection.
If this post was enjoyable or useful for you, please share it! If you have comments, questions, or feedback, you can email my personal email. To get new posts, subscribe use the RSS feed.