Sometimes you just want to visualize a small list of numbers in your Phoenix app — without pulling in a charting library or writing any JavaScript.
Luckily, with a bit of TailwindCSS and a sprinkle of animation, you can create a clean, responsive, and animated bar chart right in your LiveView template.
Let’s say we have a list of values in Elixir:
values = [19, 21, 27, 16, 37, 34, 27, 32, 33, 10]
We’ll render those as vertical bars that grow smoothly into view when the component mounts.
To make sure all bars fit within the same visual scale, we’ll normalize each value to a percentage of the maximum:
<%
max_value = Enum.max(@values)
%>
This way, the tallest bar will always reach 100% of the container height, no matter what values you pass in.
The next step is to build the HTML structure.
Here’s the complete HEEx template for your bar chart:
<%
max_value = Enum.max(@values)
%>
<div class="flex items-end gap-2 h-48 sm:h-64 md:h-80 w-full max-w-xl mx-auto">
<%= for {value, index} <- Enum.with_index(@values) do %>
<% height = value / max_value * 100 %>
<div class="flex-1 flex flex-col items-center h-full justify-end">
<div
class={[
"bg-blue-500 w-full rounded-t text-center text-white text-xs font-bold pt-2",
"animate-grow transition-all duration-700 ease-out h-[#{height}%]"
]}
style={"height: #{height}%; animation-delay: #{50}ms; transform: scaleY(0)"}
title={"#{value}"}
></div>
<span class="text-xs mt-1 text-gray-600"><%= value %></span>
</div>
<% end %>
</div>
<style>
@keyframes grow {
from {
transform: scaleY(0);
}
to {
transform: scaleY(1);
}
}
.animate-grow {
animation: grow 0.8s ease-out forwards;
}
</style>
Next, let's add the animation.
The magic is in the CSS @keyframes grow
animation:
@keyframes grow {
from {
transform: scaleY(0);
}
to {
transform: scaleY(1);
}
}
Each bar starts at scaleY(0)
and smoothly grows to its normalized height.
The origin-bottom
Tailwind class ensures that the bars expand upward instead of stretching from the middle.
The container uses Tailwind’s responsive height utilities:
h-48 sm:h-64 md:h-80
So it scales gracefully across screen sizes. Each bar also uses flex-1
, making all bars equal width, automatically filling the space available.
You now have a fully responsive, zero-JavaScript bar chart that animates beautifully when rendered.
It’s small, fast, and easy to integrate in any LiveView or static page.
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.