Liquid Fill
A copy-paste progress component in pure HTML & CSS. Zero dependencies, framework-agnostic, MIT-licensed.
ProgressHTMLCSSany framework
Copy into your project
HTML
<!-- Liquid Fill Progress (set fill via inline height on __liquid) -->
<div class="nuda-liquid-fill-progress" role="progressbar"
aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"
aria-label="60% complete">
<div class="nuda-liquid-fill-progress__liquid" style="height: 60%">
<div class="nuda-liquid-fill-progress__wave"></div>
</div>
</div>CSS
/* Liquid Fill Progress
A wavy liquid surface; the wave bob is driven by transform (translate + rotate).
Set the fill level with the inline height on __liquid.
Customize: --liquidfillp-color, --liquidfillp-size */
.nuda-liquid-fill-progress {
--liquidfillp-color: rgba(228, 255, 84, 0.85);
--liquidfillp-size: 52px;
position: relative;
width: var(--liquidfillp-size);
height: var(--liquidfillp-size);
border-radius: 50%;
border: 2px solid rgba(228, 255, 84, 0.3);
overflow: hidden;
}
.nuda-liquid-fill-progress__liquid {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: var(--liquidfillp-color);
}
.nuda-liquid-fill-progress__wave {
position: absolute;
top: -9px;
left: -50%;
width: 200%;
height: 18px;
background: var(--liquidfillp-color);
border-radius: 45%;
animation: nuda-liquid-fill-progress 2.2s linear infinite;
will-change: transform;
}
@keyframes nuda-liquid-fill-progress {
0% { transform: translateX(0) rotate(0deg); }
100% { transform: translateX(25%) rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
.nuda-liquid-fill-progress__wave { animation: none; }
}How to use Liquid Fill
Paste the HTML where you need it and the CSS into a global stylesheet (or a <style> tag). Every class is prefixed nuda- so it never collides with Tailwind or your own styles. Tweak the CSS custom properties to match your design system.
Works in React, Vue, Svelte, Astro, Next.js, Nuxt, Laravel Blade, Django, Rails — or a single .html file. No npm install, no build step.