72%
React + MotionLoaders
Anillo de progreso
Un indicador de progreso circular con el porcentaje en el centro que llega a cada valor con un muelle suave.
Ajustes
72%
112px
Código
import { motion } from "framer-motion";
const RADIUS = 42;
const CIRCUMFERENCE = 2 * Math.PI * RADIUS;
interface WatchProgressRingProps {
color?: string;
/** Progreso de 0 a 100. */
progress?: number;
size?: number;
}
export default function WatchProgressRing({
color = "#0071e3",
progress = 72,
size = 112,
}: WatchProgressRingProps) {
return (
<div
role="progressbar"
aria-valuenow={progress}
aria-valuemin={0}
aria-valuemax={100}
className="relative grid place-items-center text-[#1d1d1f] dark:text-[#f5f5f7]"
style={{ width: size, height: size }}
>
<svg viewBox="0 0 100 100" className="absolute inset-0 -rotate-90">
<circle
cx="50"
cy="50"
r={RADIUS}
fill="none"
strokeWidth="9"
className="stroke-black/5 dark:stroke-white/10"
/>
<motion.circle
cx="50"
cy="50"
r={RADIUS}
fill="none"
stroke={color}
strokeWidth="9"
strokeLinecap="round"
strokeDasharray={CIRCUMFERENCE}
animate={{ strokeDashoffset: CIRCUMFERENCE * (1 - progress / 100) }}
transition={{ type: "spring", stiffness: 300, damping: 30 }}
/>
</svg>
<motion.strong
key={progress}
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
className="text-xl"
>
{progress}%
</motion.strong>
</div>
);
}
Prompt para IA
Pégalo en ChatGPT, Claude o Cursor y adaptará el bloque a tu proyecto con estos ajustes, aunque no uses React.
Más en Loaders
Dónde usarlo
Una barra de progreso circular es ideal cuando el número importa: cuánto le falta a un perfil para estar completo, qué parte de un curso lleva un alumno o lo cerca que está alguien de su objetivo de pasos en una app de deporte. El anillo llega a cada valor con un rebote suave, como los de un reloj inteligente.
Úsalo solo si conoces el porcentaje real: un anillo que retrocede hace perder confianza. Con uno por tarjeta es suficiente. Elige un color que contraste bien con el carril gris, sobre todo en fondos claros.