Recently I was tasked with finding out why a timeline component wasn’t working in our Phoenix application, that shows the current progress of an operation as users mouse over different stages of it. It didn’t show any progress at all - not on first page load, or not when stages were hovered over.
There’s a little bit of Phoenix LiveView magic involved, but the HTML for the component boiled down to this:
The dynamic colour classes were all being whitelisted in tailwind.config.js
, so that wasn’t the problem. It turns out that setting the width of the bar via inline styles was the problem - we’d recently added a content security policy to the app to block various kinds of attacks, and it was also blocking the inline styles on the inner div
.
It turns out that HTML actually already has support for progress-type components like this - the progress
HTML element. I sometimes forget about some of these newer elements (yes, HTML5 is still new to me, get off my lawn) but it turns out that these are perfect for our purpose!
Building the progress bar#
The HTML can be simplified - for a basic unstyled bar, we can now have:
When the value
attribute changes, the page will re-render to show a progress bar filled to the given percentage (given that the max
is set to 100). No inline styles required. 😎
Styling the progress bar#
This is a little trickier. It is possible to style both the filled and unfilled sections of the bar, but we need to revisit the vendor-prefixed CSS selector days. Firefox uses -moz-progress-bar
to target the filled section, and WebKit/Blink use -webkit-progress-bar
for the unfilled section and -webkit-progress-value
for the filled section.
We can wrap these up in custom TailwindCSS variants, so that our HTML is vendor-prefix free. In your tailwind.config.js
file, this would look like:
This means that we can now use filled
and unfilled
prefixes, like dark
and hover
and any other TailwindCSS prefixes, with any existing TailwindCSS class. Background colors, gradients, animations, anything you like. You can get pretty custom!
(Note that you do need to also add the appearance-none
class, for Webkit browsers.)
Examples#
Gradients? Hovers? Sure!#
Classes on the progress bars:
“This is how close your Kickstarter is to its goal”#
This one took a bit more work, including defining some keyframes in CSS, so they can use Tailwind class names:
Wrapping the progress bar, and dynamically applying some classes depending on the value:
Where temperature(value)
is defined as:
Don’t forget to safelist any custom classes that don’t appear in their entirety in your templates! Our app used custom dynamic colours, so we needed to do this otherwise TailwindCSS wouldn’t generate them in our CSS.
You can see all code used in this blog post in the example repository on GitHub!