Using components in Phoenix templates 
Tags: phoenix, elixir, templates, components
Published: 2019-08-28 09:40:47

---
title: Using components in Phoenix templates 
published: true
description: Exploring different alternatives to use components on Phoenix templates 
tags: phoenix, elixir, templates, components
canonical_url: https://www.codegram.com/blog/phoenix-templates-components
coveer_image: https://images.unsplash.com/photo-1560961911-ac8bad98d903?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1267&q=80
---

*Originally published at [Codegram's blog](https://www.codegram.com/blog/phoenix-templates-components).*

As a mostly-Rails backend developer, **I find [Rails partials][rails-partials] confusing**. Don't get me wrong, they're useful. But they're hard to work with. In my experience, most of the times these partials will accept params, but there's no way to know what params they accept without looking at the partial content itself. And this makes me sad.

I usually write partials similar to frontend frameworks components. Minus the logic part, because I haven't found a way to have real components in Rails views. The most similar thing to what I'm looking for is [Trailblazer's `cells`][cells] (which I really like!), but they're still not quite what I'd like.

We recently worked on project that had an admin dashboard built on Phoenix based on a Bootstrap template. This kind of templates usually add their own classes on top of Bootstrap, and those components require extra HTML structure so that everything looks as expected.

"Oh, it's the perfect use case for components!", I thought.

## Componentizing Phoenix templates

Well, yes. This was the typical use case for partials. But Phoenix does not support partials explicitly as Rails does. Since Phoenix is very flexible, you can [write a `ComponentView` and dump your shared layouts there][phoenix-partials]:

```elixir
<%= render ComponentView, "tabs.html" do %>
  <%= render ComponentView, "tab.html", name: "All Products" %>
  <%= render ComponentView, "tab.html", name: "Featured" %>
<% end %>
```

The `tabs.html` file contains the wrapper layout for a tabs element, and the `tab.html` contains the layout for a single tab.

You can give a little twist to that idea, and simplify it to this:

```elixir
<%= component "tabs.html" do %>
  <%= component "tab.html", name: "All Products" %>
  <%= component "tab.html", name: "Featured" %>
<% end %>
```

Now we have a similar feature as Rails has, but since we're using a single view for all components, all component-related helpers would be written there. All together.

![Concerned darkwraith meme.](https://www.codegram.com/blog/phoenix-view-components-concerned.jpg)

## Multiple views

Exploring alternative implementations of components I found [Kim Lindholm's Phoenix component Folders repo][component-folders-repo]. If you follow the suggestions in the README file, you'll be able to have multiple component views, so that helper methods can be isolated. This allows us to write something like this:

```elixir
# lib/my_app_web/components/tabs/tabs_view.ex
defmodule MyAppWeb.Components.TabsView do
  alias MyAppWeb.Components.ComponentHelpers
  use MyAppWeb, {:view, ComponentHelpers.view_opts(:tabs)}
end

# in your template:
<%= component :tabs do %>
  <%= component :tabs, :tab, name: "All Products" %>
  <%= component :tabs, :tab, name: "Featured" %>
<% end %>
```

This got us the same functionality Rails has... with the same problems: **what params does a component accept?**

## Using helper methods to know the needed params

The fact that I couldn't see, at a glance, the params needed to build a component bugged me. I could leave it as it was, really. After all, I had been developing like that with Rails for a long time. But Elixir has a powerful toolkit to generate static docs from the documentation in the code, and I wanted to use that.

Finally, I created helper methods. Some of them wrapped the calls to the `component` methods, others created template syntax directly:

```elixir
def icon(%{icon_name: name, icon_color: color}) do
  content_tag :span, class: "icon-holder" do
    ComponentHelpers.component(:icon, color: color, icon: name)
  end
end
```

You could even use [the `~E` sigil][e-sigil] to simplify the needed code:

```elixir
def icon(%{icon_name: name, icon_color: color}) do
  ~E"""
  <span class="icon-holder">
    #{ComponentHelpers.component(:icon, color: color, icon: name)}
  </span>
  """
end
```

With that I could write static docs, and **my IDE can catch it and give me hints** about the needed parameters.

## Conclusion

This is quite a new approach for me and I probably need more opportunities to see how it matures, so I don't have a final decision on how to write components in Phoenix. I like the final approach using helper methods wrapping my components to get nice documentation, though.

What are your thoughts on this approach? Have you used something similar? Is there something I missed? 

[rails-partials]: https://guides.rubyonrails.org/layouts_and_rendering.html#using-partials
[cells]: http://trailblazer.to/gems/cells/
[phoenix-partials]: https://blog.danielberkompas.com/2017/01/17/reusable-templates-in-phoenix/
[component-folders-repo]: https://github.com/kimlindholm/phoenix_component_folders
[e-sigil]: https://hexdocs.pm/phoenix_html/2.13.3/Phoenix.HTML.html#sigil_E/2
[twitter]: https://twitter.com/codegram