evening elixir members!
I am using tailwindcss and phoenix together. And I like to create function components for certain UI components such as Card, Dropdown and etc.
Why?
because I prefer easy update of component style. And easy, <.card>card content blabla</.card>
simple easy powerful nice!
Example of Function Component
# This is an example of component usage in LiveView.
<.dropdown alignment={:end}>
<%# Use atom :end or :start to control the dropdown menu alignment. %>
<:button color={:blue}>Click here</:button>
<%# The use of atom :blue to control the button color. %>
<:item>Dropdown Item 1</:item>
<:item>Dropdown Item 2</:item>
</.dropdown>
# Here is the FunctionComponent Code
def dropdown(assigns) do
assigns =
assigns
|> assign_new(:alignment, fn -> "" end)
|> assign_new(:direction, fn -> "" end)
|> assign_new(:open, fn -> "" end)
|> assign_new(:class, fn -> "" end)
|> assign_new(:item, fn -> [] end)
~H"""
<div
class={"dropdown#{direction(@direction)}#{alignment(@alignment)}#{open(@open)}"}
id={"#{@id}-dropdown"}
>
<%= for button <- @button do %>
<label
tabindex="0"
class={
"#{button_class(button)}#{button_color(button)}#{button_outline(button)}#{button_size(button)}"
}
>
<%= render_slot(button) %>
</label>
<% end %>
<ul tabindex="0" class="dropdown-content menu p-2 w-52">
<%= for {item, i} <- Enum.with_index(@item), item_id="#{@id}-dropdown-item-#{i}" do %>
<li id={item_id}><%= render_slot(item) %></li>
<% end %>
</ul>
</div>
"""
end
# Ignore the class name, I simplify them for better reading here.
defp direction(:top), do: " dropdown-top"
defp direction(:left), do: " dropdown-left"
defp direction(_), do: ""
defp alignment(:end), do: " dropdown-end"
defp alignment(_), do: ""
defp open(true), do: " dropdown-open"
defp open(_), do: ""
# I use patterm matching to match the params
defp button_class(%{class: class}), do: class
defp button_class(_), do: ""
defp button_color(%{color: :blue}), do: " btn btn-blue m-1"
defp button_color(%{color: :gray}), do: " btn btn-gray m-1"
defp button_color(_), do: " btn m-1"
defp button_outline(%{outline: true}), do: " btn-outline"
defp button_outline(_), do: ""
defp button_size(%{size: :large}), do: " btn-lg"
defp button_size(%{size: :small}), do: " btn-sm"
defp button_size(_), do: ""
My Question Is
is it a good practice to use Atom to control the component like color={:blue}
to control the button color?
I am not sure of FunctionComponent like this is a good idea, would like to hear your opinion.
There will be more params like <.dropdown alignment={:end} direction={:top} open>
One more thing i am thinking is how to make the color={:blue}
works better, since no body know the atom is named :blue
until we have to check the FunctionComponent to see the available options. Is there a better method for this? like raising error if we set :blueblue
which is not exists