This is briefly covered in the Phoenix Guides.
What I do is similar to your (1) but I don’t add render functions in a view and call them directly.
I create a directory inside lib/my_app_web/templates
which is usually named shared
or partial
and place the “shared” templates there. For this conversation I’ll just call it shared
.
Create a template:
<%# lib/my_app_web/templates/shared/hello.html.eex %>
<strong>Hello <%= @name %>!</strong>
Then create the view:
# lib/my_app_web/views/shared_view.ex
defmodule MyAppWeb.SharedView do
use MyAppWeb, :view
# add any supporting functions for the shared templates
end
Then in any other template:
<%# lib/my_app_web/templates/page/index.html.eex %>
...
<%= render MyAppWeb.SharedView, "hello.html", name: "world" %>
...
Hello world!
If you want to nest directories under lib/my_app_web/templates/shared
like lib/my_app_web/templates/shared/components
for organization you’ll need to add pattern: "**/*",
to the view
function in lib/my_app_web.ex
like so:
...
def view do
quote do
use Phoenix.View,
root: "lib/my_app_web/templates",
+ pattern: "**/*",
namespace: MyAppWeb
...
end
end
...
Then when you use a template that is nested just provide the relative path to the template in the render function like so:
<%# lib/my_app_web/templates/page/index.html.eex %>
...
<%= render MyAppWeb.SharedView, "components/modal.html", conn: @conn, arg1: @arg1 %>
<%# If you're needing to pass many params (args) to the shared templates like arg1: @arg1, arg2: @arg2 etc., you can use `assigns` instead %>
<%= render MyAppWeb.SharedView, "components/modal.html", assigns %>
...
Hope that helps.