Skip to content

Instantly share code, notes, and snippets.

@eYinka
Last active November 7, 2024 08:54
Show Gist options
  • Save eYinka/873be69fae3ef27b103681b8a9f5e379 to your computer and use it in GitHub Desktop.
Save eYinka/873be69fae3ef27b103681b8a9f5e379 to your computer and use it in GitHub Desktop.
Tailwind CSS Radial Progress Bar
// Inspired by Tailwind Daisy UI progress bar: https://daisyui.com/components/radial-progress/
// This is a custom-made progress circular/radial progress bar with centered percentage text.
// Tested with Tailwind 3.x. Should work with lower versions of Tailwind CSS as well.
STEP 1: Add the following custom CSS:
.progress-ring__circle {
transition: stroke-dashoffset 0.35s;
transform: rotate(-90deg);
transform-origin: 50% 50%;
}
STEP 2: Build the SVG radial progress bar.
Here, I have used 'text-indigo-500', you can change the ring color to any Tailwind CSS color of your choice.
Code Explanation:
- The circumference of a circle is calculated with C = 2πr
- In this case, we assume a radius of 40
- Therefore, calculation goes thus: C= 2 × π × 40; which gives approx 251.2
- The stroke-dasharray takes the circumference value
- The progress difference is then calculated as such: circumference - ( circumference * currentProgress ) / 100
- Use javascript or css to dynamically update the value "70" to your current progress, depending on your use case.
<div class="relative w-40 h-40">
<svg class="w-full h-full" viewBox="0 0 100 100">
<!-- Background circle -->
<circle
class="text-gray-200 stroke-current"
stroke-width="10"
cx="50"
cy="50"
r="40"
fill="transparent"
></circle>
<!-- Progress circle -->
<circle
class="text-indigo-500 progress-ring__circle stroke-current"
stroke-width="10"
stroke-linecap="round"
cx="50"
cy="50"
r="40"
fill="transparent"
stroke-dasharray="251.2"
stroke-dashoffset="calc(251.2px - (251.2px * 70) / 100)"
></circle>
<!-- Center text -->
<text x="50" y="50" font-family="Verdana" font-size="12" text-anchor="middle" alignment-baseline="middle">70%</text>
</svg>
</div>
That's all! You should have a nice looking radial progress bar using Tailwind CSS now.
Demo: https://play.tailwindcss.com/53s5OjCLix
Cheers :)
@eYinka
Copy link
Author

eYinka commented Apr 12, 2024

Apologies guys! I messed up my calculations. The circumference of the circle didn't match my explanation, hence, the value inaccuracy. I have edited the code to fit and get it all giddy! Also added explanatory comments and new demo link :)

Good spot @RS-Roshi @loisgomez @zharzone

@stri8ed
Copy link

stri8ed commented May 1, 2024

FYI, this does not work in FireFox.

@SkyNotBlueEnough
Copy link

SkyNotBlueEnough commented Jun 4, 2024

Doesn't work with Firefox and Safari because of missing units in the stroke-dashoffset calculation.

stroke-dashoffset="calc(251.2px - (251.2px * 30) / 100)"

This works fine on FireFox.

https://stackoverflow.com/questions/65849051/calc-not-working-with-stroke-dashoffset-in-safari-and-firefox

@eYinka
Copy link
Author

eYinka commented Jun 16, 2024

Great find @SkyNotBlueEnough

I'd update the code. Thank you!

@maxotuteye
Copy link

I made a react component for this, with dynamic calculations here https://gist.github.com/maxotuteye/86dc828106847c471a0abbb11a631550

@eYinka
Copy link
Author

eYinka commented Jun 22, 2024

Cool stuff! @maxotuteye

@career-tokens
Copy link

Thanks @eYinka for this
It helped a lot!

@Omarmarei
Copy link

This worked for me in React typescript :

`// components/CircularProgressBar.tsx
import React from 'react';

interface CircularProgressBarProps {
percentage: number;
size?: number;
strokeWidth?: number;
}

const CircularProgressBar: React.FC = ({
percentage,
size = 120,
strokeWidth = 10,
}) => {
const radius = (size - strokeWidth) / 2;
const circumference = 2 * Math.PI * radius;
const offset = circumference - (percentage / 100) * circumference;

return (
<svg
width={size}
height={size}
viewBox={0 0 ${size} ${size}}
className="circular-progress-bar"
>
<circle
className="circle-bg"
stroke="#e6e6e6"
strokeWidth={strokeWidth}
fill="none"
cx={size / 2}
cy={size / 2}
r={radius}
/>
<circle
className="circle-progress"
stroke="#3b82f6"
strokeWidth={strokeWidth}
strokeLinecap="round"
fill="none"
cx={size / 2}
cy={size / 2}
r={radius}
strokeDasharray={circumference}
strokeDashoffset={offset}
transform={rotate(-90 ${size / 2} ${size / 2})} // Rotate the circle to start at the top
/>

{${percentage}%}


);
};

export default CircularProgressBar;
`

@lumotroph
Copy link

Brilliant stuff! Thank you for sharing your work.
I made some improvements / set some defaults on a react.js version made by
@maxotuteye over here, take a look if you'd like :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment