Gradient Progress Bars — Animated HTML CSS JS Snippet

Gradient Progress Bars · Loaders · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Gradient shimmer animation
background-size: 200% 100% + background-position keyframe animation creates a continuous shimmer sweep without JavaScript.
Striped moving bars
repeating-linear-gradient(45deg, ...) layered over a gradient base, animated with background-position — creates diagonal moving stripe pattern.
CSS custom property width
--p custom property on each bar drives width: var(--p) — set fill amount with a single inline style attribute.
Segmented step indicator
Flex row of equal segments with .done, .active, and default states. Active segment pulses with an opacity keyframe animation.
Skill bars load animation
width: 0% on init, animated to data-p + '%' via a 200ms-delayed setTimeout — ensures visible animation after first paint.
Interactive +/− controls
adjustBar(delta) clamps value to 0–100 and updates both the CSS custom property and label text simultaneously.
Five colour variants
Indigo, cyan, red/amber, green, and purple — covering the most common status and brand colour schemes.
Smooth width transition
cubic-bezier(.4,0,.2,1) easing on width — smooth deceleration that feels physical rather than linear.

About this UI Snippet

Gradient Progress Bars — CSS Shimmer, Stripe Animation, Segmented Steps & Skill Bars

Screenshot of the Gradient Progress Bars snippet rendered live

Progress bars are among the most versatile UI components — used for file uploads, page load indicators, onboarding completion, skill showcases, storage usage displays, and interactive data visualisations. This snippet delivers five distinct progress bar styles in a single cohesive component: animated gradient shimmer bars, moving stripe bars, segmented step indicators, animating-in skill bars, and an interactive bar with +/- controls.

Getting progress bars right requires solving several CSS challenges simultaneously: the fill width must animate smoothly, the gradient must feel alive (not static), stripes must animate without background-position glitches, and the on-load animation must feel purposeful rather than mechanical.

Animated gradient shimmer

The shimmer effect uses a wider-than-container gradient: background: linear-gradient(90deg, #6366f1, #8b5cf6, #6366f1) with background-size: 200% 100%. The @keyframes shimmer animates background-position from 200% 0 to -200% 0 over 2 seconds — this creates a continuous sweep of lighter purple across the bar. The background-size: 200% means the gradient repeats: as the right edge exits, the left edge enters, creating a seamless loop.

The fill width is driven by a --p CSS custom property set inline on each bar: style="--p:72%". The width: var(--p, 0%) in CSS reads this property. Animating from 0% to the target width is handled by transition: width .6s cubic-bezier(.4,0,.2,1) — the same Material Design easing used for panel motions.

Striped moving bars

Striped bars layer two backgrounds: a repeating diagonal stripe pattern using repeating-linear-gradient(45deg, ...) over a solid gradient base. The stripe animation uses background-position increments — moving by one stripe-width (24px) per second creates the illusion of movement. The key implementation detail is setting background-position as the animation property (not background-image) since position-only animation avoids repaints.

Segmented step indicator

The step bar uses a flex row of equal-width <div class="seg"> elements with 4px gaps. Completed steps get .done (solid indigo), the active step gets .active (gradient with a pulsing opacity animation at 1.4s ease-in-out), and future steps remain light grey. This pattern is used in multi-step forms and onboarding flows.

Skill bars with load animation

Skill bars start at width: 0% and animate to their target via a setTimeout on DOMContentLoaded — the 200ms delay ensures the page has painted before the animation runs, making it feel like a triggered reveal rather than a flash. The data-p attribute stores the target percentage, read by JS and set as bar.style.width.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSFive grouped sections appear: gradient shimmer bars, striped animated bars, segmented steps, skill bars, and an interactive bar with controls.
  2. 2
    Watch the animationsGradient bars shimmer continuously. Striped bars have diagonal lines moving right-to-left. Skill bars animate in from 0% to their target width on load.
  3. 3
    Use the +/- buttonsThe interactive bar section adjusts "Project completion" in 5% or 10% steps. The bar animates smoothly between values.
  4. 4
    Set progress valuesChange style="--p:72%" on any .prog-bar to set its fill width. Values from 0% to 100% work directly.
  5. 5
    Change the colour variantSwap bar-indigo, bar-cyan, bar-red, bar-green, or bar-purple on any .prog-bar to change the gradient colour scheme.
  6. 6
    Update the segmented stepsAdd or remove <div class="seg"> elements. Apply .done to completed steps and .active to the current step. The flex layout adjusts automatically.

Real-world uses

Common Use Cases

File upload and download progress
The striped animated bar is the universal pattern for in-progress operations — stripes communicate activity even when the exact percentage is uncertain.
Onboarding completion flows
The segmented step indicator maps directly to onboarding steps — users can see how many steps remain. Pair with a multi-step form.
Dashboard storage and resource usage
The gradient shimmer bars with percentage labels display storage quotas, CPU/memory usage, and API rate limit consumption in dashboard cards.
Portfolio skill showcases
The skill bars section is a classic portfolio pattern — technology names on the left, animated fill bars showing proficiency level, percentage on the right.
Survey and quiz completion
A thin progress bar at the top of a multi-question form shows survey completion — reduces abandonment by showing users how close to done they are.
Fundraising and goal trackers
Non-profits and crowdfunding pages use gradient bars to show funding progress toward a goal — the shimmer animation adds energy to the fundraising display.

Got questions?

Frequently Asked Questions

Use an IntersectionObserver on each .prog-bar. When the bar enters the viewport, set bar.style.setProperty('--p', targetWidth). Start with --p: 0% in CSS so bars don't animate before they're visible. See the reveal on scroll snippet for the observer pattern.

Make the bar position: relative and add a <span class="label"> child with position: absolute; right: 6px; top: 50%; transform: translateY(-50%). Ensure the bar height is at least 18px. Hide the label when --p < 15% to avoid overflow.

Call bar.style.setProperty('--p', value + '%') to update the fill width. For upload progress: read event.loaded / event.total * 100 from an XHR or Fetch progress event and call setProperty on each progress update.

Create a ProgressBar component with {label, value, variant, striped} props. value drives style={{['--p']: value + '%'}}. variant applies the colour class. striped conditionally adds the stripe class. The skill bar animation uses useEffect with a setTimeout(() => setWidth(targetValue), 200).

Gradient Progress Bars — Export as HTML, React, Vue, Angular & Tailwind

HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Gradient Progress Bars</title>
  <style>
    *{box-sizing:border-box;margin:0;padding:0}
    body{font-family:system-ui,sans-serif;background:#f8fafc;min-height:100vh;padding:28px 20px}
    .page{max-width:580px;margin:0 auto;display:flex;flex-direction:column;gap:28px}
    
    .group{background:#fff;border:1.5px solid #e2e8f0;border-radius:16px;padding:20px 22px;display:flex;flex-direction:column;gap:16px}
    .group-title{font-size:12px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:#94a3b8;margin-bottom:2px}
    
    .prog-wrap{display:flex;flex-direction:column;gap:6px}
    .prog-header{display:flex;justify-content:space-between;align-items:center}
    .prog-label{font-size:13px;font-weight:600;color:#334155}
    .prog-val{font-size:12px;font-weight:700;color:#64748b}
    
    .prog-track{height:8px;background:#f1f5f9;border-radius:20px;overflow:hidden}
    .prog-bar{height:100%;border-radius:20px;width:var(--p,0%);transition:width .6s cubic-bezier(.4,0,.2,1);background-size:200% 100%;animation:shimmer 2s linear infinite}
    
    .bar-indigo{background:linear-gradient(90deg,#6366f1,#8b5cf6,#6366f1)}
    .bar-cyan{background:linear-gradient(90deg,#0ea5e9,#06b6d4,#0ea5e9)}
    .bar-red{background:linear-gradient(90deg,#f59e0b,#ef4444,#f59e0b)}
    .bar-green{background:linear-gradient(90deg,#10b981,#059669,#10b981)}
    .bar-purple{background:linear-gradient(90deg,#8b5cf6,#6366f1,#8b5cf6)}
    
    @keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}
    
    .bar-stripe{background-image:repeating-linear-gradient(
      45deg,
      transparent,transparent 6px,
      rgba(255,255,255,.18) 6px,rgba(255,255,255,.18) 12px
    ),linear-gradient(90deg,#10b981,#059669)}
    .bar-stripe.bar-purple{background-image:repeating-linear-gradient(
      45deg,
      transparent,transparent 6px,
      rgba(255,255,255,.18) 6px,rgba(255,255,255,.18) 12px
    ),linear-gradient(90deg,#8b5cf6,#6366f1);animation:stripe-move 1s linear infinite}
    .bar-stripe{animation:stripe-move 1s linear infinite}
    @keyframes stripe-move{0%{background-position:0 0}100%{background-position:24px 0}}
    
    .seg-track{display:flex;gap:4px}
    .seg{flex:1;height:6px;border-radius:4px;background:#e2e8f0;transition:background .3s}
    .seg.done{background:#6366f1}
    .seg.active{background:linear-gradient(90deg,#6366f1,#8b5cf6);animation:pulse-seg 1.4s ease-in-out infinite}
    @keyframes pulse-seg{0%,100%{opacity:1}50%{opacity:.6}}
    
    .skills{display:flex;flex-direction:column;gap:10px}
    .skill-row{display:grid;grid-template-columns:100px 1fr 36px;align-items:center;gap:10px}
    .skill-name{font-size:12px;font-weight:600;color:#334155}
    .skill-track{height:7px;background:#f1f5f9;border-radius:20px;overflow:hidden}
    .skill-bar{height:100%;border-radius:20px;background:linear-gradient(90deg,#6366f1,#8b5cf6);width:0%;transition:width .8s cubic-bezier(.4,0,.2,1)}
    .skill-pct{font-size:11px;font-weight:700;color:#6366f1;text-align:right}
    
    .btn-row{display:flex;gap:8px;flex-wrap:wrap}
    .ctrl-btn{padding:6px 14px;border-radius:8px;border:1.5px solid #e2e8f0;background:#fff;color:#475569;font-size:12px;font-weight:600;cursor:pointer;transition:all .15s;font-family:inherit}
    .ctrl-btn:hover{border-color:#c7d2fe;color:#6366f1}
    .ctrl-btn.primary{background:#6366f1;border-color:#6366f1;color:#fff}
    .ctrl-btn.primary:hover{background:#4f46e5}
  </style>
</head>
<body>
  <div class="page">
    <section class="group">
      <h3 class="group-title">Animated Gradient</h3>
      <div class="prog-wrap">
        <div class="prog-header"><span class="prog-label">Storage Used</span><span class="prog-val">72%</span></div>
        <div class="prog-track"><div class="prog-bar bar-indigo" style="--p:72%"></div></div>
      </div>
      <div class="prog-wrap">
        <div class="prog-header"><span class="prog-label">CPU Usage</span><span class="prog-val">48%</span></div>
        <div class="prog-track"><div class="prog-bar bar-cyan" style="--p:48%"></div></div>
      </div>
      <div class="prog-wrap">
        <div class="prog-header"><span class="prog-label">Memory</span><span class="prog-val">89%</span></div>
        <div class="prog-track"><div class="prog-bar bar-red" style="--p:89%"></div></div>
      </div>
    </section>
  
    <section class="group">
      <h3 class="group-title">Striped Animated</h3>
      <div class="prog-wrap">
        <div class="prog-header"><span class="prog-label">Uploading files…</span><span class="prog-val">63%</span></div>
        <div class="prog-track"><div class="prog-bar bar-stripe bar-green" style="--p:63%"></div></div>
      </div>
      <div class="prog-wrap">
        <div class="prog-header"><span class="prog-label">Syncing database</span><span class="prog-val">31%</span></div>
        <div class="prog-track"><div class="prog-bar bar-stripe bar-purple" style="--p:31%"></div></div>
      </div>
    </section>
  
    <section class="group">
      <h3 class="group-title">Segmented / Steps</h3>
      <div class="prog-wrap">
        <div class="prog-header"><span class="prog-label">Onboarding progress</span><span class="prog-val">Step 3 of 5</span></div>
        <div class="seg-track">
          <div class="seg done"></div>
          <div class="seg done"></div>
          <div class="seg active"></div>
          <div class="seg"></div>
          <div class="seg"></div>
        </div>
      </div>
    </section>
  
    <section class="group">
      <h3 class="group-title">Skill Bars</h3>
      <div class="skills">
        <div class="skill-row">
          <span class="skill-name">React</span>
          <div class="skill-track"><div class="skill-bar" data-p="90"></div></div>
          <span class="skill-pct">90%</span>
        </div>
        <div class="skill-row">
          <span class="skill-name">TypeScript</span>
          <div class="skill-track"><div class="skill-bar" data-p="78"></div></div>
          <span class="skill-pct">78%</span>
        </div>
        <div class="skill-row">
          <span class="skill-name">Node.js</span>
          <div class="skill-track"><div class="skill-bar" data-p="65"></div></div>
          <span class="skill-pct">65%</span>
        </div>
        <div class="skill-row">
          <span class="skill-name">CSS / Design</span>
          <div class="skill-track"><div class="skill-bar" data-p="85"></div></div>
          <span class="skill-pct">85%</span>
        </div>
      </div>
    </section>
  
    <section class="group">
      <h3 class="group-title">Interactive — Click to update</h3>
      <div class="prog-wrap">
        <div class="prog-header"><span class="prog-label">Project completion</span><span class="prog-val" id="liveVal">55%</span></div>
        <div class="prog-track"><div class="prog-bar bar-indigo" id="liveBar" style="--p:55%"></div></div>
      </div>
      <div class="btn-row">
        <button class="ctrl-btn" onclick="adjustBar(-10)">−10%</button>
        <button class="ctrl-btn" onclick="adjustBar(-5)">−5%</button>
        <button class="ctrl-btn primary" onclick="adjustBar(5)">+5%</button>
        <button class="ctrl-btn primary" onclick="adjustBar(10)">+10%</button>
      </div>
    </section>
  </div>
  <script>
    // Animate skill bars on load
    window.addEventListener('DOMContentLoaded', () => {
      document.querySelectorAll('.skill-bar').forEach(bar => {
        setTimeout(() => { bar.style.width = bar.dataset.p + '%'; }, 200);
      });
    });
    
    // Interactive progress bar
    let liveP = 55;
    function adjustBar(delta) {
      liveP = Math.min(100, Math.max(0, liveP + delta));
      const bar = document.getElementById('liveBar');
      bar.style.setProperty('--p', liveP + '%');
      document.getElementById('liveVal').textContent = liveP + '%';
    }
  </script>
</body>
</html>
Tailwind
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Gradient Progress Bars</title>
  <!-- Tailwind CSS v3+ — arbitrary value classes (e.g. bg-[#0f172a]) are valid -->
  <script src="https://cdn.tailwindcss.com"></script>
  <style>
    @keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}

    @keyframes stripe-move{0%{background-position:0 0}100%{background-position:24px 0}}

    @keyframes pulse-seg{0%,100%{opacity:1}50%{opacity:.6}}

    * {
      box-sizing:border-box;margin:0;padding:0
    }

    body {
      font-family:system-ui,sans-serif;background:#f8fafc;min-height:100vh;padding:28px 20px
    }

    .bar-stripe.bar-purple {
      background-image:repeating-linear-gradient(
      45deg,
      transparent,transparent 6px,
      rgba(255,255,255,.18) 6px,rgba(255,255,255,.18) 12px
    ),linear-gradient(90deg,#8b5cf6,#6366f1);animation:stripe-move 1s linear infinite
    }

    .seg.done {
      background:#6366f1
    }

    .seg.active {
      background:linear-gradient(90deg,#6366f1,#8b5cf6);animation:pulse-seg 1.4s ease-in-out infinite
    }

    .ctrl-btn.primary {
      background:#6366f1;border-color:#6366f1;color:#fff
    }

    .ctrl-btn.primary:hover {
      background:#4f46e5
    }
  </style>
</head>
<body>
  <div class="max-w-[580px] my-0 mx-auto flex flex-col gap-7">
    <section class="bg-[#fff] border rounded-2xl py-5 px-[22px] flex flex-col gap-4">
      <h3 class="text-xs font-bold tracking-[.06em] uppercase text-[#94a3b8] mb-0.5">Animated Gradient</h3>
      <div class="flex flex-col gap-1.5">
        <div class="flex justify-between items-center"><span class="text-[13px] font-semibold text-[#334155]">Storage Used</span><span class="text-xs font-bold text-[#64748b]">72%</span></div>
        <div class="h-2 bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div class="h-full rounded-[20px] w-[var(--p,0%)] [transition:width_.6s_cubic-bezier(.4,0,.2,1)] bg-[size:200%_100%] [animation:shimmer_2s_linear_infinite] [background:linear-gradient(90deg,#6366f1,#8b5cf6,#6366f1)]" style="--p:72%"></div></div>
      </div>
      <div class="flex flex-col gap-1.5">
        <div class="flex justify-between items-center"><span class="text-[13px] font-semibold text-[#334155]">CPU Usage</span><span class="text-xs font-bold text-[#64748b]">48%</span></div>
        <div class="h-2 bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div class="h-full rounded-[20px] w-[var(--p,0%)] [transition:width_.6s_cubic-bezier(.4,0,.2,1)] bg-[size:200%_100%] [animation:shimmer_2s_linear_infinite] [background:linear-gradient(90deg,#0ea5e9,#06b6d4,#0ea5e9)]" style="--p:48%"></div></div>
      </div>
      <div class="flex flex-col gap-1.5">
        <div class="flex justify-between items-center"><span class="text-[13px] font-semibold text-[#334155]">Memory</span><span class="text-xs font-bold text-[#64748b]">89%</span></div>
        <div class="h-2 bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div class="h-full rounded-[20px] w-[var(--p,0%)] [transition:width_.6s_cubic-bezier(.4,0,.2,1)] bg-[size:200%_100%] [animation:shimmer_2s_linear_infinite] [background:linear-gradient(90deg,#f59e0b,#ef4444,#f59e0b)]" style="--p:89%"></div></div>
      </div>
    </section>
  
    <section class="bg-[#fff] border rounded-2xl py-5 px-[22px] flex flex-col gap-4">
      <h3 class="text-xs font-bold tracking-[.06em] uppercase text-[#94a3b8] mb-0.5">Striped Animated</h3>
      <div class="flex flex-col gap-1.5">
        <div class="flex justify-between items-center"><span class="text-[13px] font-semibold text-[#334155]">Uploading files…</span><span class="text-xs font-bold text-[#64748b]">63%</span></div>
        <div class="h-2 bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div class="h-full rounded-[20px] w-[var(--p,0%)] [transition:width_.6s_cubic-bezier(.4,0,.2,1)] bg-[size:200%_100%] [animation:shimmer_2s_linear_infinite] bar-stripe [background-image:repeating-linear-gradient(
  __45deg,
  __transparent,transparent_6px,
  __rgba(255,255,255,.18)_6px,rgba(255,255,255,.18)_12px
  ),linear-gradient(90deg,#10b981,#059669)] [animation:stripe-move_1s_linear_infinite] [background:linear-gradient(90deg,#10b981,#059669,#10b981)]" style="--p:63%"></div></div>
      </div>
      <div class="flex flex-col gap-1.5">
        <div class="flex justify-between items-center"><span class="text-[13px] font-semibold text-[#334155]">Syncing database</span><span class="text-xs font-bold text-[#64748b]">31%</span></div>
        <div class="h-2 bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div class="h-full rounded-[20px] w-[var(--p,0%)] [transition:width_.6s_cubic-bezier(.4,0,.2,1)] bg-[size:200%_100%] [animation:shimmer_2s_linear_infinite] bar-stripe [background-image:repeating-linear-gradient(
  __45deg,
  __transparent,transparent_6px,
  __rgba(255,255,255,.18)_6px,rgba(255,255,255,.18)_12px
  ),linear-gradient(90deg,#10b981,#059669)] [animation:stripe-move_1s_linear_infinite] bar-purple [background:linear-gradient(90deg,#8b5cf6,#6366f1,#8b5cf6)]" style="--p:31%"></div></div>
      </div>
    </section>
  
    <section class="bg-[#fff] border rounded-2xl py-5 px-[22px] flex flex-col gap-4">
      <h3 class="text-xs font-bold tracking-[.06em] uppercase text-[#94a3b8] mb-0.5">Segmented / Steps</h3>
      <div class="flex flex-col gap-1.5">
        <div class="flex justify-between items-center"><span class="text-[13px] font-semibold text-[#334155]">Onboarding progress</span><span class="text-xs font-bold text-[#64748b]">Step 3 of 5</span></div>
        <div class="flex gap-1">
          <div class="seg flex-1 h-1.5 rounded bg-[#e2e8f0] [transition:background_.3s] done"></div>
          <div class="seg flex-1 h-1.5 rounded bg-[#e2e8f0] [transition:background_.3s] done"></div>
          <div class="seg flex-1 h-1.5 rounded bg-[#e2e8f0] [transition:background_.3s] active"></div>
          <div class="seg flex-1 h-1.5 rounded bg-[#e2e8f0] [transition:background_.3s]"></div>
          <div class="seg flex-1 h-1.5 rounded bg-[#e2e8f0] [transition:background_.3s]"></div>
        </div>
      </div>
    </section>
  
    <section class="bg-[#fff] border rounded-2xl py-5 px-[22px] flex flex-col gap-4">
      <h3 class="text-xs font-bold tracking-[.06em] uppercase text-[#94a3b8] mb-0.5">Skill Bars</h3>
      <div class="flex flex-col gap-2.5">
        <div class="grid grid-cols-1 items-center gap-2.5">
          <span class="text-xs font-semibold text-[#334155]">React</span>
          <div class="h-[7px] bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div class="skill-bar h-full rounded-[20px] [background:linear-gradient(90deg,#6366f1,#8b5cf6)] w-0 [transition:width_.8s_cubic-bezier(.4,0,.2,1)]" data-p="90"></div></div>
          <span class="text-[11px] font-bold text-[#6366f1] text-right">90%</span>
        </div>
        <div class="grid grid-cols-1 items-center gap-2.5">
          <span class="text-xs font-semibold text-[#334155]">TypeScript</span>
          <div class="h-[7px] bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div class="skill-bar h-full rounded-[20px] [background:linear-gradient(90deg,#6366f1,#8b5cf6)] w-0 [transition:width_.8s_cubic-bezier(.4,0,.2,1)]" data-p="78"></div></div>
          <span class="text-[11px] font-bold text-[#6366f1] text-right">78%</span>
        </div>
        <div class="grid grid-cols-1 items-center gap-2.5">
          <span class="text-xs font-semibold text-[#334155]">Node.js</span>
          <div class="h-[7px] bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div class="skill-bar h-full rounded-[20px] [background:linear-gradient(90deg,#6366f1,#8b5cf6)] w-0 [transition:width_.8s_cubic-bezier(.4,0,.2,1)]" data-p="65"></div></div>
          <span class="text-[11px] font-bold text-[#6366f1] text-right">65%</span>
        </div>
        <div class="grid grid-cols-1 items-center gap-2.5">
          <span class="text-xs font-semibold text-[#334155]">CSS / Design</span>
          <div class="h-[7px] bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div class="skill-bar h-full rounded-[20px] [background:linear-gradient(90deg,#6366f1,#8b5cf6)] w-0 [transition:width_.8s_cubic-bezier(.4,0,.2,1)]" data-p="85"></div></div>
          <span class="text-[11px] font-bold text-[#6366f1] text-right">85%</span>
        </div>
      </div>
    </section>
  
    <section class="bg-[#fff] border rounded-2xl py-5 px-[22px] flex flex-col gap-4">
      <h3 class="text-xs font-bold tracking-[.06em] uppercase text-[#94a3b8] mb-0.5">Interactive — Click to update</h3>
      <div class="flex flex-col gap-1.5">
        <div class="flex justify-between items-center"><span class="text-[13px] font-semibold text-[#334155]">Project completion</span><span class="text-xs font-bold text-[#64748b]" id="liveVal">55%</span></div>
        <div class="h-2 bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div class="h-full rounded-[20px] w-[var(--p,0%)] [transition:width_.6s_cubic-bezier(.4,0,.2,1)] bg-[size:200%_100%] [animation:shimmer_2s_linear_infinite] [background:linear-gradient(90deg,#6366f1,#8b5cf6,#6366f1)]" id="liveBar" style="--p:55%"></div></div>
      </div>
      <div class="flex gap-2 flex-wrap">
        <button class="ctrl-btn py-1.5 px-3.5 rounded-lg border bg-[#fff] text-[#475569] text-xs font-semibold cursor-pointer [transition:all_.15s] font-[inherit] hover:border-[#c7d2fe] hover:text-[#6366f1]" onclick="adjustBar(-10)">−10%</button>
        <button class="ctrl-btn py-1.5 px-3.5 rounded-lg border bg-[#fff] text-[#475569] text-xs font-semibold cursor-pointer [transition:all_.15s] font-[inherit] hover:border-[#c7d2fe] hover:text-[#6366f1]" onclick="adjustBar(-5)">−5%</button>
        <button class="ctrl-btn py-1.5 px-3.5 rounded-lg border bg-[#fff] text-[#475569] text-xs font-semibold cursor-pointer [transition:all_.15s] font-[inherit] hover:border-[#c7d2fe] hover:text-[#6366f1] primary" onclick="adjustBar(5)">+5%</button>
        <button class="ctrl-btn py-1.5 px-3.5 rounded-lg border bg-[#fff] text-[#475569] text-xs font-semibold cursor-pointer [transition:all_.15s] font-[inherit] hover:border-[#c7d2fe] hover:text-[#6366f1] primary" onclick="adjustBar(10)">+10%</button>
      </div>
    </section>
  </div>
  <script>
    // Animate skill bars on load
    window.addEventListener('DOMContentLoaded', () => {
      document.querySelectorAll('.skill-bar').forEach(bar => {
        setTimeout(() => { bar.style.width = bar.dataset.p + '%'; }, 200);
      });
    });
    
    // Interactive progress bar
    let liveP = 55;
    function adjustBar(delta) {
      liveP = Math.min(100, Math.max(0, liveP + delta));
      const bar = document.getElementById('liveBar');
      bar.style.setProperty('--p', liveP + '%');
      document.getElementById('liveVal').textContent = liveP + '%';
    }
  </script>
</body>
</html>
React
import React, { useEffect } from 'react';

// CSS — optionally move to GradientProgressBars.module.css
const css = `
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:system-ui,sans-serif;background:#f8fafc;min-height:100vh;padding:28px 20px}
.page{max-width:580px;margin:0 auto;display:flex;flex-direction:column;gap:28px}

.group{background:#fff;border:1.5px solid #e2e8f0;border-radius:16px;padding:20px 22px;display:flex;flex-direction:column;gap:16px}
.group-title{font-size:12px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:#94a3b8;margin-bottom:2px}

.prog-wrap{display:flex;flex-direction:column;gap:6px}
.prog-header{display:flex;justify-content:space-between;align-items:center}
.prog-label{font-size:13px;font-weight:600;color:#334155}
.prog-val{font-size:12px;font-weight:700;color:#64748b}

.prog-track{height:8px;background:#f1f5f9;border-radius:20px;overflow:hidden}
.prog-bar{height:100%;border-radius:20px;width:var(--p,0%);transition:width .6s cubic-bezier(.4,0,.2,1);background-size:200% 100%;animation:shimmer 2s linear infinite}

.bar-indigo{background:linear-gradient(90deg,#6366f1,#8b5cf6,#6366f1)}
.bar-cyan{background:linear-gradient(90deg,#0ea5e9,#06b6d4,#0ea5e9)}
.bar-red{background:linear-gradient(90deg,#f59e0b,#ef4444,#f59e0b)}
.bar-green{background:linear-gradient(90deg,#10b981,#059669,#10b981)}
.bar-purple{background:linear-gradient(90deg,#8b5cf6,#6366f1,#8b5cf6)}

@keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}

.bar-stripe{background-image:repeating-linear-gradient(
  45deg,
  transparent,transparent 6px,
  rgba(255,255,255,.18) 6px,rgba(255,255,255,.18) 12px
),linear-gradient(90deg,#10b981,#059669)}
.bar-stripe.bar-purple{background-image:repeating-linear-gradient(
  45deg,
  transparent,transparent 6px,
  rgba(255,255,255,.18) 6px,rgba(255,255,255,.18) 12px
),linear-gradient(90deg,#8b5cf6,#6366f1);animation:stripe-move 1s linear infinite}
.bar-stripe{animation:stripe-move 1s linear infinite}
@keyframes stripe-move{0%{background-position:0 0}100%{background-position:24px 0}}

.seg-track{display:flex;gap:4px}
.seg{flex:1;height:6px;border-radius:4px;background:#e2e8f0;transition:background .3s}
.seg.done{background:#6366f1}
.seg.active{background:linear-gradient(90deg,#6366f1,#8b5cf6);animation:pulse-seg 1.4s ease-in-out infinite}
@keyframes pulse-seg{0%,100%{opacity:1}50%{opacity:.6}}

.skills{display:flex;flex-direction:column;gap:10px}
.skill-row{display:grid;grid-template-columns:100px 1fr 36px;align-items:center;gap:10px}
.skill-name{font-size:12px;font-weight:600;color:#334155}
.skill-track{height:7px;background:#f1f5f9;border-radius:20px;overflow:hidden}
.skill-bar{height:100%;border-radius:20px;background:linear-gradient(90deg,#6366f1,#8b5cf6);width:0%;transition:width .8s cubic-bezier(.4,0,.2,1)}
.skill-pct{font-size:11px;font-weight:700;color:#6366f1;text-align:right}

.btn-row{display:flex;gap:8px;flex-wrap:wrap}
.ctrl-btn{padding:6px 14px;border-radius:8px;border:1.5px solid #e2e8f0;background:#fff;color:#475569;font-size:12px;font-weight:600;cursor:pointer;transition:all .15s;font-family:inherit}
.ctrl-btn:hover{border-color:#c7d2fe;color:#6366f1}
.ctrl-btn.primary{background:#6366f1;border-color:#6366f1;color:#fff}
.ctrl-btn.primary:hover{background:#4f46e5}
`;

export default function GradientProgressBars() {
  // Auto-generated escape hatch: the original snippet's vanilla JS runs once
  // after mount and queries the rendered DOM. For idiomatic React, lift this
  // into state + handlers.
  useEffect(() => {
    const _listeners = [];
    const _originalAddEventListener = EventTarget.prototype.addEventListener;
    EventTarget.prototype.addEventListener = function(type, listener, options) {
      _listeners.push({ target: this, type, listener, options });
      return _originalAddEventListener.call(this, type, listener, options);
    };
    // Animate skill bars on load
    window.addEventListener('DOMContentLoaded', () => {
      document.querySelectorAll('.skill-bar').forEach(bar => {
        setTimeout(() => { bar.style.width = bar.dataset.p + '%'; }, 200);
      });
    });
    
    // Interactive progress bar
    let liveP = 55;
    function adjustBar(delta) {
      liveP = Math.min(100, Math.max(0, liveP + delta));
      const bar = document.getElementById('liveBar');
      bar.style.setProperty('--p', liveP + '%');
      document.getElementById('liveVal').textContent = liveP + '%';
    }
    // Cleanup: restore addEventListener and remove all listeners
    return () => {
      EventTarget.prototype.addEventListener = _originalAddEventListener;
      for (const { target, type, listener, options } of _listeners) {
        target.removeEventListener(type, listener, options);
      }
    };

    // Expose handlers used by inline JSX events to the global scope
    if (typeof adjustBar === 'function') window.adjustBar = adjustBar;
  }, []);

  return (
    <>
      <style>{css}</style>
      <div className="page">
        <section className="group">
          <h3 className="group-title">Animated Gradient</h3>
          <div className="prog-wrap">
            <div className="prog-header"><span className="prog-label">Storage Used</span><span className="prog-val">72%</span></div>
            <div className="prog-track"><div className="prog-bar bar-indigo" style={{ '--p': '72%' }}></div></div>
          </div>
          <div className="prog-wrap">
            <div className="prog-header"><span className="prog-label">CPU Usage</span><span className="prog-val">48%</span></div>
            <div className="prog-track"><div className="prog-bar bar-cyan" style={{ '--p': '48%' }}></div></div>
          </div>
          <div className="prog-wrap">
            <div className="prog-header"><span className="prog-label">Memory</span><span className="prog-val">89%</span></div>
            <div className="prog-track"><div className="prog-bar bar-red" style={{ '--p': '89%' }}></div></div>
          </div>
        </section>
      
        <section className="group">
          <h3 className="group-title">Striped Animated</h3>
          <div className="prog-wrap">
            <div className="prog-header"><span className="prog-label">Uploading files…</span><span className="prog-val">63%</span></div>
            <div className="prog-track"><div className="prog-bar bar-stripe bar-green" style={{ '--p': '63%' }}></div></div>
          </div>
          <div className="prog-wrap">
            <div className="prog-header"><span className="prog-label">Syncing database</span><span className="prog-val">31%</span></div>
            <div className="prog-track"><div className="prog-bar bar-stripe bar-purple" style={{ '--p': '31%' }}></div></div>
          </div>
        </section>
      
        <section className="group">
          <h3 className="group-title">Segmented / Steps</h3>
          <div className="prog-wrap">
            <div className="prog-header"><span className="prog-label">Onboarding progress</span><span className="prog-val">Step 3 of 5</span></div>
            <div className="seg-track">
              <div className="seg done"></div>
              <div className="seg done"></div>
              <div className="seg active"></div>
              <div className="seg"></div>
              <div className="seg"></div>
            </div>
          </div>
        </section>
      
        <section className="group">
          <h3 className="group-title">Skill Bars</h3>
          <div className="skills">
            <div className="skill-row">
              <span className="skill-name">React</span>
              <div className="skill-track"><div className="skill-bar" data-p="90"></div></div>
              <span className="skill-pct">90%</span>
            </div>
            <div className="skill-row">
              <span className="skill-name">TypeScript</span>
              <div className="skill-track"><div className="skill-bar" data-p="78"></div></div>
              <span className="skill-pct">78%</span>
            </div>
            <div className="skill-row">
              <span className="skill-name">Node.js</span>
              <div className="skill-track"><div className="skill-bar" data-p="65"></div></div>
              <span className="skill-pct">65%</span>
            </div>
            <div className="skill-row">
              <span className="skill-name">CSS / Design</span>
              <div className="skill-track"><div className="skill-bar" data-p="85"></div></div>
              <span className="skill-pct">85%</span>
            </div>
          </div>
        </section>
      
        <section className="group">
          <h3 className="group-title">Interactive — Click to update</h3>
          <div className="prog-wrap">
            <div className="prog-header"><span className="prog-label">Project completion</span><span className="prog-val" id="liveVal">55%</span></div>
            <div className="prog-track"><div className="prog-bar bar-indigo" id="liveBar" style={{ '--p': '55%' }}></div></div>
          </div>
          <div className="btn-row">
            <button className="ctrl-btn" onClick={(event) => { adjustBar(-10) }}>−10%</button>
            <button className="ctrl-btn" onClick={(event) => { adjustBar(-5) }}>−5%</button>
            <button className="ctrl-btn primary" onClick={(event) => { adjustBar(5) }}>+5%</button>
            <button className="ctrl-btn primary" onClick={(event) => { adjustBar(10) }}>+10%</button>
          </div>
        </section>
      </div>
    </>
  );
}
React + Tailwind
import React, { useEffect } from 'react';
// Requires Tailwind CSS v3+ — https://tailwindcss.com/docs/installation
// Arbitrary value classes (e.g. bg-[#0f172a]) are valid Tailwind v3+

export default function GradientProgressBars() {
  // Auto-generated escape hatch: the original snippet's vanilla JS runs once
  // after mount and queries the rendered DOM. For idiomatic React, lift this
  // into state + handlers.
  useEffect(() => {
    const _listeners = [];
    const _originalAddEventListener = EventTarget.prototype.addEventListener;
    EventTarget.prototype.addEventListener = function(type, listener, options) {
      _listeners.push({ target: this, type, listener, options });
      return _originalAddEventListener.call(this, type, listener, options);
    };
    // Animate skill bars on load
    window.addEventListener('DOMContentLoaded', () => {
      document.querySelectorAll('.skill-bar').forEach(bar => {
        setTimeout(() => { bar.style.width = bar.dataset.p + '%'; }, 200);
      });
    });
    
    // Interactive progress bar
    let liveP = 55;
    function adjustBar(delta) {
      liveP = Math.min(100, Math.max(0, liveP + delta));
      const bar = document.getElementById('liveBar');
      bar.style.setProperty('--p', liveP + '%');
      document.getElementById('liveVal').textContent = liveP + '%';
    }
    // Cleanup: restore addEventListener and remove all listeners
    return () => {
      EventTarget.prototype.addEventListener = _originalAddEventListener;
      for (const { target, type, listener, options } of _listeners) {
        target.removeEventListener(type, listener, options);
      }
    };

    // Expose handlers used by inline JSX events to the global scope
    if (typeof adjustBar === 'function') window.adjustBar = adjustBar;
  }, []);

  return (
    <>
      <style>{`
@keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}

@keyframes stripe-move{0%{background-position:0 0}100%{background-position:24px 0}}

@keyframes pulse-seg{0%,100%{opacity:1}50%{opacity:.6}}

* {
  box-sizing:border-box;margin:0;padding:0
}

body {
  font-family:system-ui,sans-serif;background:#f8fafc;min-height:100vh;padding:28px 20px
}

.bar-stripe.bar-purple {
  background-image:repeating-linear-gradient(
  45deg,
  transparent,transparent 6px,
  rgba(255,255,255,.18) 6px,rgba(255,255,255,.18) 12px
),linear-gradient(90deg,#8b5cf6,#6366f1);animation:stripe-move 1s linear infinite
}

.seg.done {
  background:#6366f1
}

.seg.active {
  background:linear-gradient(90deg,#6366f1,#8b5cf6);animation:pulse-seg 1.4s ease-in-out infinite
}

.ctrl-btn.primary {
  background:#6366f1;border-color:#6366f1;color:#fff
}

.ctrl-btn.primary:hover {
  background:#4f46e5
}
      `}</style>
      <div className="max-w-[580px] my-0 mx-auto flex flex-col gap-7">
        <section className="bg-[#fff] border rounded-2xl py-5 px-[22px] flex flex-col gap-4">
          <h3 className="text-xs font-bold tracking-[.06em] uppercase text-[#94a3b8] mb-0.5">Animated Gradient</h3>
          <div className="flex flex-col gap-1.5">
            <div className="flex justify-between items-center"><span className="text-[13px] font-semibold text-[#334155]">Storage Used</span><span className="text-xs font-bold text-[#64748b]">72%</span></div>
            <div className="h-2 bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div className="h-full rounded-[20px] w-[var(--p,0%)] [transition:width_.6s_cubic-bezier(.4,0,.2,1)] bg-[size:200%_100%] [animation:shimmer_2s_linear_infinite] [background:linear-gradient(90deg,#6366f1,#8b5cf6,#6366f1)]" style={{ '--p': '72%' }}></div></div>
          </div>
          <div className="flex flex-col gap-1.5">
            <div className="flex justify-between items-center"><span className="text-[13px] font-semibold text-[#334155]">CPU Usage</span><span className="text-xs font-bold text-[#64748b]">48%</span></div>
            <div className="h-2 bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div className="h-full rounded-[20px] w-[var(--p,0%)] [transition:width_.6s_cubic-bezier(.4,0,.2,1)] bg-[size:200%_100%] [animation:shimmer_2s_linear_infinite] [background:linear-gradient(90deg,#0ea5e9,#06b6d4,#0ea5e9)]" style={{ '--p': '48%' }}></div></div>
          </div>
          <div className="flex flex-col gap-1.5">
            <div className="flex justify-between items-center"><span className="text-[13px] font-semibold text-[#334155]">Memory</span><span className="text-xs font-bold text-[#64748b]">89%</span></div>
            <div className="h-2 bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div className="h-full rounded-[20px] w-[var(--p,0%)] [transition:width_.6s_cubic-bezier(.4,0,.2,1)] bg-[size:200%_100%] [animation:shimmer_2s_linear_infinite] [background:linear-gradient(90deg,#f59e0b,#ef4444,#f59e0b)]" style={{ '--p': '89%' }}></div></div>
          </div>
        </section>
      
        <section className="bg-[#fff] border rounded-2xl py-5 px-[22px] flex flex-col gap-4">
          <h3 className="text-xs font-bold tracking-[.06em] uppercase text-[#94a3b8] mb-0.5">Striped Animated</h3>
          <div className="flex flex-col gap-1.5">
            <div className="flex justify-between items-center"><span className="text-[13px] font-semibold text-[#334155]">Uploading files…</span><span className="text-xs font-bold text-[#64748b]">63%</span></div>
            <div className="h-2 bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div className="h-full rounded-[20px] w-[var(--p,0%)] [transition:width_.6s_cubic-bezier(.4,0,.2,1)] bg-[size:200%_100%] [animation:shimmer_2s_linear_infinite] bar-stripe [background-image:repeating-linear-gradient(
      __45deg,
      __transparent,transparent_6px,
      __rgba(255,255,255,.18)_6px,rgba(255,255,255,.18)_12px
      ),linear-gradient(90deg,#10b981,#059669)] [animation:stripe-move_1s_linear_infinite] [background:linear-gradient(90deg,#10b981,#059669,#10b981)]" style={{ '--p': '63%' }}></div></div>
          </div>
          <div className="flex flex-col gap-1.5">
            <div className="flex justify-between items-center"><span className="text-[13px] font-semibold text-[#334155]">Syncing database</span><span className="text-xs font-bold text-[#64748b]">31%</span></div>
            <div className="h-2 bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div className="h-full rounded-[20px] w-[var(--p,0%)] [transition:width_.6s_cubic-bezier(.4,0,.2,1)] bg-[size:200%_100%] [animation:shimmer_2s_linear_infinite] bar-stripe [background-image:repeating-linear-gradient(
      __45deg,
      __transparent,transparent_6px,
      __rgba(255,255,255,.18)_6px,rgba(255,255,255,.18)_12px
      ),linear-gradient(90deg,#10b981,#059669)] [animation:stripe-move_1s_linear_infinite] bar-purple [background:linear-gradient(90deg,#8b5cf6,#6366f1,#8b5cf6)]" style={{ '--p': '31%' }}></div></div>
          </div>
        </section>
      
        <section className="bg-[#fff] border rounded-2xl py-5 px-[22px] flex flex-col gap-4">
          <h3 className="text-xs font-bold tracking-[.06em] uppercase text-[#94a3b8] mb-0.5">Segmented / Steps</h3>
          <div className="flex flex-col gap-1.5">
            <div className="flex justify-between items-center"><span className="text-[13px] font-semibold text-[#334155]">Onboarding progress</span><span className="text-xs font-bold text-[#64748b]">Step 3 of 5</span></div>
            <div className="flex gap-1">
              <div className="seg flex-1 h-1.5 rounded bg-[#e2e8f0] [transition:background_.3s] done"></div>
              <div className="seg flex-1 h-1.5 rounded bg-[#e2e8f0] [transition:background_.3s] done"></div>
              <div className="seg flex-1 h-1.5 rounded bg-[#e2e8f0] [transition:background_.3s] active"></div>
              <div className="seg flex-1 h-1.5 rounded bg-[#e2e8f0] [transition:background_.3s]"></div>
              <div className="seg flex-1 h-1.5 rounded bg-[#e2e8f0] [transition:background_.3s]"></div>
            </div>
          </div>
        </section>
      
        <section className="bg-[#fff] border rounded-2xl py-5 px-[22px] flex flex-col gap-4">
          <h3 className="text-xs font-bold tracking-[.06em] uppercase text-[#94a3b8] mb-0.5">Skill Bars</h3>
          <div className="flex flex-col gap-2.5">
            <div className="grid grid-cols-1 items-center gap-2.5">
              <span className="text-xs font-semibold text-[#334155]">React</span>
              <div className="h-[7px] bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div className="skill-bar h-full rounded-[20px] [background:linear-gradient(90deg,#6366f1,#8b5cf6)] w-0 [transition:width_.8s_cubic-bezier(.4,0,.2,1)]" data-p="90"></div></div>
              <span className="text-[11px] font-bold text-[#6366f1] text-right">90%</span>
            </div>
            <div className="grid grid-cols-1 items-center gap-2.5">
              <span className="text-xs font-semibold text-[#334155]">TypeScript</span>
              <div className="h-[7px] bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div className="skill-bar h-full rounded-[20px] [background:linear-gradient(90deg,#6366f1,#8b5cf6)] w-0 [transition:width_.8s_cubic-bezier(.4,0,.2,1)]" data-p="78"></div></div>
              <span className="text-[11px] font-bold text-[#6366f1] text-right">78%</span>
            </div>
            <div className="grid grid-cols-1 items-center gap-2.5">
              <span className="text-xs font-semibold text-[#334155]">Node.js</span>
              <div className="h-[7px] bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div className="skill-bar h-full rounded-[20px] [background:linear-gradient(90deg,#6366f1,#8b5cf6)] w-0 [transition:width_.8s_cubic-bezier(.4,0,.2,1)]" data-p="65"></div></div>
              <span className="text-[11px] font-bold text-[#6366f1] text-right">65%</span>
            </div>
            <div className="grid grid-cols-1 items-center gap-2.5">
              <span className="text-xs font-semibold text-[#334155]">CSS / Design</span>
              <div className="h-[7px] bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div className="skill-bar h-full rounded-[20px] [background:linear-gradient(90deg,#6366f1,#8b5cf6)] w-0 [transition:width_.8s_cubic-bezier(.4,0,.2,1)]" data-p="85"></div></div>
              <span className="text-[11px] font-bold text-[#6366f1] text-right">85%</span>
            </div>
          </div>
        </section>
      
        <section className="bg-[#fff] border rounded-2xl py-5 px-[22px] flex flex-col gap-4">
          <h3 className="text-xs font-bold tracking-[.06em] uppercase text-[#94a3b8] mb-0.5">Interactive — Click to update</h3>
          <div className="flex flex-col gap-1.5">
            <div className="flex justify-between items-center"><span className="text-[13px] font-semibold text-[#334155]">Project completion</span><span className="text-xs font-bold text-[#64748b]" id="liveVal">55%</span></div>
            <div className="h-2 bg-[#f1f5f9] rounded-[20px] overflow-hidden"><div className="h-full rounded-[20px] w-[var(--p,0%)] [transition:width_.6s_cubic-bezier(.4,0,.2,1)] bg-[size:200%_100%] [animation:shimmer_2s_linear_infinite] [background:linear-gradient(90deg,#6366f1,#8b5cf6,#6366f1)]" id="liveBar" style={{ '--p': '55%' }}></div></div>
          </div>
          <div className="flex gap-2 flex-wrap">
            <button className="ctrl-btn py-1.5 px-3.5 rounded-lg border bg-[#fff] text-[#475569] text-xs font-semibold cursor-pointer [transition:all_.15s] font-[inherit] hover:border-[#c7d2fe] hover:text-[#6366f1]" onClick={(event) => { adjustBar(-10) }}>−10%</button>
            <button className="ctrl-btn py-1.5 px-3.5 rounded-lg border bg-[#fff] text-[#475569] text-xs font-semibold cursor-pointer [transition:all_.15s] font-[inherit] hover:border-[#c7d2fe] hover:text-[#6366f1]" onClick={(event) => { adjustBar(-5) }}>−5%</button>
            <button className="ctrl-btn py-1.5 px-3.5 rounded-lg border bg-[#fff] text-[#475569] text-xs font-semibold cursor-pointer [transition:all_.15s] font-[inherit] hover:border-[#c7d2fe] hover:text-[#6366f1] primary" onClick={(event) => { adjustBar(5) }}>+5%</button>
            <button className="ctrl-btn py-1.5 px-3.5 rounded-lg border bg-[#fff] text-[#475569] text-xs font-semibold cursor-pointer [transition:all_.15s] font-[inherit] hover:border-[#c7d2fe] hover:text-[#6366f1] primary" onClick={(event) => { adjustBar(10) }}>+10%</button>
          </div>
        </section>
      </div>
    </>
  );
}
Vue
<template>
  <div class="page">
    <section class="group">
      <h3 class="group-title">Animated Gradient</h3>
      <div class="prog-wrap">
        <div class="prog-header"><span class="prog-label">Storage Used</span><span class="prog-val">72%</span></div>
        <div class="prog-track"><div class="prog-bar bar-indigo" style="--p:72%"></div></div>
      </div>
      <div class="prog-wrap">
        <div class="prog-header"><span class="prog-label">CPU Usage</span><span class="prog-val">48%</span></div>
        <div class="prog-track"><div class="prog-bar bar-cyan" style="--p:48%"></div></div>
      </div>
      <div class="prog-wrap">
        <div class="prog-header"><span class="prog-label">Memory</span><span class="prog-val">89%</span></div>
        <div class="prog-track"><div class="prog-bar bar-red" style="--p:89%"></div></div>
      </div>
    </section>
  
    <section class="group">
      <h3 class="group-title">Striped Animated</h3>
      <div class="prog-wrap">
        <div class="prog-header"><span class="prog-label">Uploading files…</span><span class="prog-val">63%</span></div>
        <div class="prog-track"><div class="prog-bar bar-stripe bar-green" style="--p:63%"></div></div>
      </div>
      <div class="prog-wrap">
        <div class="prog-header"><span class="prog-label">Syncing database</span><span class="prog-val">31%</span></div>
        <div class="prog-track"><div class="prog-bar bar-stripe bar-purple" style="--p:31%"></div></div>
      </div>
    </section>
  
    <section class="group">
      <h3 class="group-title">Segmented / Steps</h3>
      <div class="prog-wrap">
        <div class="prog-header"><span class="prog-label">Onboarding progress</span><span class="prog-val">Step 3 of 5</span></div>
        <div class="seg-track">
          <div class="seg done"></div>
          <div class="seg done"></div>
          <div class="seg active"></div>
          <div class="seg"></div>
          <div class="seg"></div>
        </div>
      </div>
    </section>
  
    <section class="group">
      <h3 class="group-title">Skill Bars</h3>
      <div class="skills">
        <div class="skill-row">
          <span class="skill-name">React</span>
          <div class="skill-track"><div class="skill-bar" data-p="90"></div></div>
          <span class="skill-pct">90%</span>
        </div>
        <div class="skill-row">
          <span class="skill-name">TypeScript</span>
          <div class="skill-track"><div class="skill-bar" data-p="78"></div></div>
          <span class="skill-pct">78%</span>
        </div>
        <div class="skill-row">
          <span class="skill-name">Node.js</span>
          <div class="skill-track"><div class="skill-bar" data-p="65"></div></div>
          <span class="skill-pct">65%</span>
        </div>
        <div class="skill-row">
          <span class="skill-name">CSS / Design</span>
          <div class="skill-track"><div class="skill-bar" data-p="85"></div></div>
          <span class="skill-pct">85%</span>
        </div>
      </div>
    </section>
  
    <section class="group">
      <h3 class="group-title">Interactive — Click to update</h3>
      <div class="prog-wrap">
        <div class="prog-header"><span class="prog-label">Project completion</span><span class="prog-val" id="liveVal">55%</span></div>
        <div class="prog-track"><div class="prog-bar bar-indigo" id="liveBar" style="--p:55%"></div></div>
      </div>
      <div class="btn-row">
        <button class="ctrl-btn" @click="adjustBar(-10)">−10%</button>
        <button class="ctrl-btn" @click="adjustBar(-5)">−5%</button>
        <button class="ctrl-btn primary" @click="adjustBar(5)">+5%</button>
        <button class="ctrl-btn primary" @click="adjustBar(10)">+10%</button>
      </div>
    </section>
  </div>
</template>

<script setup>
import { onMounted } from 'vue';

// Interactive progress bar
let liveP = 55;
function adjustBar(delta) {
  liveP = Math.min(100, Math.max(0, liveP + delta));
  const bar = document.getElementById('liveBar');
  bar.style.setProperty('--p', liveP + '%');
  document.getElementById('liveVal').textContent = liveP + '%';
}

onMounted(() => {
  // Animate skill bars on load
  window.addEventListener('DOMContentLoaded', () => {
    document.querySelectorAll('.skill-bar').forEach(bar => {
      setTimeout(() => { bar.style.width = bar.dataset.p + '%'; }, 200);
    });
  });
});
</script>

<style scoped>
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:system-ui,sans-serif;background:#f8fafc;min-height:100vh;padding:28px 20px}
.page{max-width:580px;margin:0 auto;display:flex;flex-direction:column;gap:28px}

.group{background:#fff;border:1.5px solid #e2e8f0;border-radius:16px;padding:20px 22px;display:flex;flex-direction:column;gap:16px}
.group-title{font-size:12px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:#94a3b8;margin-bottom:2px}

.prog-wrap{display:flex;flex-direction:column;gap:6px}
.prog-header{display:flex;justify-content:space-between;align-items:center}
.prog-label{font-size:13px;font-weight:600;color:#334155}
.prog-val{font-size:12px;font-weight:700;color:#64748b}

.prog-track{height:8px;background:#f1f5f9;border-radius:20px;overflow:hidden}
.prog-bar{height:100%;border-radius:20px;width:var(--p,0%);transition:width .6s cubic-bezier(.4,0,.2,1);background-size:200% 100%;animation:shimmer 2s linear infinite}

.bar-indigo{background:linear-gradient(90deg,#6366f1,#8b5cf6,#6366f1)}
.bar-cyan{background:linear-gradient(90deg,#0ea5e9,#06b6d4,#0ea5e9)}
.bar-red{background:linear-gradient(90deg,#f59e0b,#ef4444,#f59e0b)}
.bar-green{background:linear-gradient(90deg,#10b981,#059669,#10b981)}
.bar-purple{background:linear-gradient(90deg,#8b5cf6,#6366f1,#8b5cf6)}

@keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}

.bar-stripe{background-image:repeating-linear-gradient(
  45deg,
  transparent,transparent 6px,
  rgba(255,255,255,.18) 6px,rgba(255,255,255,.18) 12px
),linear-gradient(90deg,#10b981,#059669)}
.bar-stripe.bar-purple{background-image:repeating-linear-gradient(
  45deg,
  transparent,transparent 6px,
  rgba(255,255,255,.18) 6px,rgba(255,255,255,.18) 12px
),linear-gradient(90deg,#8b5cf6,#6366f1);animation:stripe-move 1s linear infinite}
.bar-stripe{animation:stripe-move 1s linear infinite}
@keyframes stripe-move{0%{background-position:0 0}100%{background-position:24px 0}}

.seg-track{display:flex;gap:4px}
.seg{flex:1;height:6px;border-radius:4px;background:#e2e8f0;transition:background .3s}
.seg.done{background:#6366f1}
.seg.active{background:linear-gradient(90deg,#6366f1,#8b5cf6);animation:pulse-seg 1.4s ease-in-out infinite}
@keyframes pulse-seg{0%,100%{opacity:1}50%{opacity:.6}}

.skills{display:flex;flex-direction:column;gap:10px}
.skill-row{display:grid;grid-template-columns:100px 1fr 36px;align-items:center;gap:10px}
.skill-name{font-size:12px;font-weight:600;color:#334155}
.skill-track{height:7px;background:#f1f5f9;border-radius:20px;overflow:hidden}
.skill-bar{height:100%;border-radius:20px;background:linear-gradient(90deg,#6366f1,#8b5cf6);width:0%;transition:width .8s cubic-bezier(.4,0,.2,1)}
.skill-pct{font-size:11px;font-weight:700;color:#6366f1;text-align:right}

.btn-row{display:flex;gap:8px;flex-wrap:wrap}
.ctrl-btn{padding:6px 14px;border-radius:8px;border:1.5px solid #e2e8f0;background:#fff;color:#475569;font-size:12px;font-weight:600;cursor:pointer;transition:all .15s;font-family:inherit}
.ctrl-btn:hover{border-color:#c7d2fe;color:#6366f1}
.ctrl-btn.primary{background:#6366f1;border-color:#6366f1;color:#fff}
.ctrl-btn.primary:hover{background:#4f46e5}
</style>
Angular
// @ts-nocheck
// Note: vanilla JS DOM manipulation is preserved as-is inside ngAfterViewInit().
// For idiomatic Angular, replace document.getElementById() with @ViewChild() refs
// and move state into component properties with two-way binding.
import { Component, AfterViewInit, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-gradient-progress-bars',
  standalone: true,
  imports: [CommonModule],
  encapsulation: ViewEncapsulation.None,
  template: `
    <div class="page">
      <section class="group">
        <h3 class="group-title">Animated Gradient</h3>
        <div class="prog-wrap">
          <div class="prog-header"><span class="prog-label">Storage Used</span><span class="prog-val">72%</span></div>
          <div class="prog-track"><div class="prog-bar bar-indigo" style="--p:72%"></div></div>
        </div>
        <div class="prog-wrap">
          <div class="prog-header"><span class="prog-label">CPU Usage</span><span class="prog-val">48%</span></div>
          <div class="prog-track"><div class="prog-bar bar-cyan" style="--p:48%"></div></div>
        </div>
        <div class="prog-wrap">
          <div class="prog-header"><span class="prog-label">Memory</span><span class="prog-val">89%</span></div>
          <div class="prog-track"><div class="prog-bar bar-red" style="--p:89%"></div></div>
        </div>
      </section>
    
      <section class="group">
        <h3 class="group-title">Striped Animated</h3>
        <div class="prog-wrap">
          <div class="prog-header"><span class="prog-label">Uploading files…</span><span class="prog-val">63%</span></div>
          <div class="prog-track"><div class="prog-bar bar-stripe bar-green" style="--p:63%"></div></div>
        </div>
        <div class="prog-wrap">
          <div class="prog-header"><span class="prog-label">Syncing database</span><span class="prog-val">31%</span></div>
          <div class="prog-track"><div class="prog-bar bar-stripe bar-purple" style="--p:31%"></div></div>
        </div>
      </section>
    
      <section class="group">
        <h3 class="group-title">Segmented / Steps</h3>
        <div class="prog-wrap">
          <div class="prog-header"><span class="prog-label">Onboarding progress</span><span class="prog-val">Step 3 of 5</span></div>
          <div class="seg-track">
            <div class="seg done"></div>
            <div class="seg done"></div>
            <div class="seg active"></div>
            <div class="seg"></div>
            <div class="seg"></div>
          </div>
        </div>
      </section>
    
      <section class="group">
        <h3 class="group-title">Skill Bars</h3>
        <div class="skills">
          <div class="skill-row">
            <span class="skill-name">React</span>
            <div class="skill-track"><div class="skill-bar" data-p="90"></div></div>
            <span class="skill-pct">90%</span>
          </div>
          <div class="skill-row">
            <span class="skill-name">TypeScript</span>
            <div class="skill-track"><div class="skill-bar" data-p="78"></div></div>
            <span class="skill-pct">78%</span>
          </div>
          <div class="skill-row">
            <span class="skill-name">Node.js</span>
            <div class="skill-track"><div class="skill-bar" data-p="65"></div></div>
            <span class="skill-pct">65%</span>
          </div>
          <div class="skill-row">
            <span class="skill-name">CSS / Design</span>
            <div class="skill-track"><div class="skill-bar" data-p="85"></div></div>
            <span class="skill-pct">85%</span>
          </div>
        </div>
      </section>
    
      <section class="group">
        <h3 class="group-title">Interactive — Click to update</h3>
        <div class="prog-wrap">
          <div class="prog-header"><span class="prog-label">Project completion</span><span class="prog-val" id="liveVal">55%</span></div>
          <div class="prog-track"><div class="prog-bar bar-indigo" id="liveBar" style="--p:55%"></div></div>
        </div>
        <div class="btn-row">
          <button class="ctrl-btn" (click)="adjustBar(-10)">−10%</button>
          <button class="ctrl-btn" (click)="adjustBar(-5)">−5%</button>
          <button class="ctrl-btn primary" (click)="adjustBar(5)">+5%</button>
          <button class="ctrl-btn primary" (click)="adjustBar(10)">+10%</button>
        </div>
      </section>
    </div>
  `,
  styles: [`
    *{box-sizing:border-box;margin:0;padding:0}
    body{font-family:system-ui,sans-serif;background:#f8fafc;min-height:100vh;padding:28px 20px}
    .page{max-width:580px;margin:0 auto;display:flex;flex-direction:column;gap:28px}
    
    .group{background:#fff;border:1.5px solid #e2e8f0;border-radius:16px;padding:20px 22px;display:flex;flex-direction:column;gap:16px}
    .group-title{font-size:12px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:#94a3b8;margin-bottom:2px}
    
    .prog-wrap{display:flex;flex-direction:column;gap:6px}
    .prog-header{display:flex;justify-content:space-between;align-items:center}
    .prog-label{font-size:13px;font-weight:600;color:#334155}
    .prog-val{font-size:12px;font-weight:700;color:#64748b}
    
    .prog-track{height:8px;background:#f1f5f9;border-radius:20px;overflow:hidden}
    .prog-bar{height:100%;border-radius:20px;width:var(--p,0%);transition:width .6s cubic-bezier(.4,0,.2,1);background-size:200% 100%;animation:shimmer 2s linear infinite}
    
    .bar-indigo{background:linear-gradient(90deg,#6366f1,#8b5cf6,#6366f1)}
    .bar-cyan{background:linear-gradient(90deg,#0ea5e9,#06b6d4,#0ea5e9)}
    .bar-red{background:linear-gradient(90deg,#f59e0b,#ef4444,#f59e0b)}
    .bar-green{background:linear-gradient(90deg,#10b981,#059669,#10b981)}
    .bar-purple{background:linear-gradient(90deg,#8b5cf6,#6366f1,#8b5cf6)}
    
    @keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}
    
    .bar-stripe{background-image:repeating-linear-gradient(
      45deg,
      transparent,transparent 6px,
      rgba(255,255,255,.18) 6px,rgba(255,255,255,.18) 12px
    ),linear-gradient(90deg,#10b981,#059669)}
    .bar-stripe.bar-purple{background-image:repeating-linear-gradient(
      45deg,
      transparent,transparent 6px,
      rgba(255,255,255,.18) 6px,rgba(255,255,255,.18) 12px
    ),linear-gradient(90deg,#8b5cf6,#6366f1);animation:stripe-move 1s linear infinite}
    .bar-stripe{animation:stripe-move 1s linear infinite}
    @keyframes stripe-move{0%{background-position:0 0}100%{background-position:24px 0}}
    
    .seg-track{display:flex;gap:4px}
    .seg{flex:1;height:6px;border-radius:4px;background:#e2e8f0;transition:background .3s}
    .seg.done{background:#6366f1}
    .seg.active{background:linear-gradient(90deg,#6366f1,#8b5cf6);animation:pulse-seg 1.4s ease-in-out infinite}
    @keyframes pulse-seg{0%,100%{opacity:1}50%{opacity:.6}}
    
    .skills{display:flex;flex-direction:column;gap:10px}
    .skill-row{display:grid;grid-template-columns:100px 1fr 36px;align-items:center;gap:10px}
    .skill-name{font-size:12px;font-weight:600;color:#334155}
    .skill-track{height:7px;background:#f1f5f9;border-radius:20px;overflow:hidden}
    .skill-bar{height:100%;border-radius:20px;background:linear-gradient(90deg,#6366f1,#8b5cf6);width:0%;transition:width .8s cubic-bezier(.4,0,.2,1)}
    .skill-pct{font-size:11px;font-weight:700;color:#6366f1;text-align:right}
    
    .btn-row{display:flex;gap:8px;flex-wrap:wrap}
    .ctrl-btn{padding:6px 14px;border-radius:8px;border:1.5px solid #e2e8f0;background:#fff;color:#475569;font-size:12px;font-weight:600;cursor:pointer;transition:all .15s;font-family:inherit}
    .ctrl-btn:hover{border-color:#c7d2fe;color:#6366f1}
    .ctrl-btn.primary{background:#6366f1;border-color:#6366f1;color:#fff}
    .ctrl-btn.primary:hover{background:#4f46e5}
  `]
})
export class GradientProgressBarsComponent implements AfterViewInit {
  ngAfterViewInit(): void {
    // Animate skill bars on load
    window.addEventListener('DOMContentLoaded', () => {
      document.querySelectorAll('.skill-bar').forEach(bar => {
        setTimeout(() => { bar.style.width = bar.dataset.p + '%'; }, 200);
      });
    });
    
    // Interactive progress bar
    let liveP = 55;
    function adjustBar(delta) {
      liveP = Math.min(100, Math.max(0, liveP + delta));
      const bar = document.getElementById('liveBar');
      bar.style.setProperty('--p', liveP + '%');
      document.getElementById('liveVal').textContent = liveP + '%';
    }

    // Bind inline-handler functions to the component so the template can call them
    Object.assign(this, { adjustBar });
  }
}