Lottie Scroll Bar Chart — Bars Grow on Scroll

Lottie Scroll Bar Chart · Scroll · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Lottie JSON built in code with keyframe helpers — no exported file, nothing to fetch or 404
Bars grow with a transform scale from a base-aligned origin, not by animating height from the centre
Every animated keyframe carries i/o easing tangents so lottie-web interpolates instead of holding
Per-column stagger produces a left-to-right build instead of a flat simultaneous pop
Colours interpolate across the bars from a start to an end hue, driven by column index
autoplay: false + goToAndStop(frame, true): scroll position, not a timer, decides the frame
Fully reversible — scrolling up shrinks the bars back down in reverse for free
Data-driven: edit one HEIGHTS array to plot your own values, bars and colours adapt

About this UI Snippet

How to Build a Scroll-Driven Lottie Bar Chart That Grows Column by Column

Screenshot of the Lottie Scroll Bar Chart snippet rendered live

The Lottie Scroll Bar Chart snippet grows a row of coloured bars up from a baseline as the visitor scrolls, one column staggered a beat behind the next, and shrinks them back down on the way up. Nothing plays on a timer — the scrollbar drives the animation frame by frame — and the whole chart is generated in JavaScript rather than exported from After Effects, so the growth mechanism is fully visible in the code.

Lottie is JSON, and here it is assembled in code

A Lottie animation is a JSON document of vector layers and keyframes. Instead of fetching one, this snippet builds the animationData object directly and passes it to lottie.loadAnimation, so there is nothing to host and nothing that can 404. A small layer helper stamps out each bar, and a keyframe helper assembles the growth animation with the easing tangents lottie-web requires.

Growing a bar with scale, not height

The natural instinct is to animate a rectangle's height, but that grows it from the centre in both directions. The trick used here is to grow the bar with a transform scale instead. Each bar is a group whose origin sits exactly on the baseline; inside it, the rectangle is positioned so its whole body is above that origin. Animating only the group's vertical scale from 0 to 100 then stretches the bar upward from the base, exactly like a real column filling in — no repositioning maths required. At scale 0 the bar collapses onto the baseline and is invisible; at 100 it stands at full height.

The one keyframe detail that matters

When you author a Lottie by hand, every animated keyframe must carry its i (in) and o (out) bezier tangents. Omit them and lottie-web treats the keyframe as a hold keyframe: it never interpolates, so a scale animated 0 to 100 stays stuck at 0 and the bar never grows. The keyframe helper here attaches linear tangents to every keyframe, which is what makes the bars actually rise.

The column stagger

The bars do not all grow at once. Each bar's scale animation is offset by its column index — column two starts a beat after column one, and so on — so the chart fills in as a left-to-right sweep rather than a flat simultaneous pop. That single per-column delay is what gives the reveal its rhythm; without it the chart would feel like a snap rather than a build.

Autoplay off, scroll on

The animation is loaded with autoplay: false so its internal clock never runs. A GSAP ScrollTrigger pins the stage and scrubs a single plain value from 0 to 1 over a range several viewport-heights tall, and a requestAnimationFrame loop reads that value every frame and calls anim.goToAndStop(p * (totalFrames - 1), true). The true tells lottie-web the value is a frame number, and goToAndStop renders a single still frame without starting playback, so the chart's growth is welded to scroll position. Because lottie-web interpolates between keyframes, fractional frames render smoothly.

Reversible for free

Deriving the frame from one scrubbed value means scrolling up produces smaller values, so the bars shrink back down in reverse order with no extra code. A smoothed scrub: 0.5 lets the growth glide toward the scroll position rather than snapping to every wheel tick, and the caption fades out the instant the chart begins to build. Pair it with the Lottie scroll line draw for a trend line, or the Lottie scroll scrub ring for a summary stat.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You do not have to reverse-engineer how a JSON file becomes a scroll-grown chart. Paste this snippet's HTML, CSS, and JS into an AI assistant like Claude and ask it to walk through why the bars grow with a scale transform instead of an animated height, or why every keyframe needs i/o tangents. The same assistant can help you extend it — ask it to add value labels above each bar, animate a horizontal grid line, feed the HEIGHTS array from real data, or turn the bars into a grouped or stacked chart. Treat the code as a conversation starter, not a finished artifact.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a "scroll-driven Lottie bar chart" in plain HTML, CSS, and JavaScript using lottie-web and GSAP's ScrollTrigger plugin, both from a CDN (no bundler).

Requirements:
- A pinned full-height section with a centered container div for the Lottie, an intro caption overlay, and a live "percent grown" read-out.
- Build the Lottie as an inline animationData JSON object (leave a comment showing how to swap it for path: 'your-animation.json'). Include a keyframe helper that ALWAYS attaches i/o easing tangents (linear) — without them lottie-web holds the value and nothing animates.
- The animation is a row of coloured bars that grow up from a baseline. Grow each bar with a transform scale, not by animating height: place the bar's rectangle above a base-aligned group origin and animate the group's vertical scale from 0 to 100. Colours interpolate across the bars by index.
- Stagger each bar's growth by its column index so the chart fills in left to right rather than all at once.
- Load with lottie.loadAnimation using renderer 'svg', loop false, autoplay FALSE.
- Register a GSAP tween on a ScrollTrigger targeting the pinned section, with pin true, start at top top, scrub around 0.5, and an end several hundred percent tall, animating one value p from 0 to 1.
- In a requestAnimationFrame loop, read p and call anim.goToAndStop(p * (anim.totalFrames - 1), true), update the read-out, and fade the caption out once p passes a small threshold.
- Confirm scrolling up shrinks the bars back down.

Step by step

How to Use

  1. 1
    Load the three CDN scriptsAdd lottie.min.js, gsap.min.js, and ScrollTrigger.min.js from the CDN panel, in that order.
  2. 2
    Paste the HTML, CSS, and JSA baseline and a "% grown" read-out appear centred in a pinned stage, with the bars starting at zero height.
  3. 3
    Scroll downThe bars grow up from the baseline, column by column in a left-to-right stagger, tied directly to scroll position.
  4. 4
    Scroll back upThe bars shrink back down exactly, because goToAndStop seeks a single frame rather than playing on a timer.
  5. 5
    Set your own dataEdit the HEIGHTS array (values 0 to 1) and the bar count to plot your own figures; colours interpolate automatically.
  6. 6
    Tune the revealChange the per-column stagger, the growth duration, or the ScrollTrigger end value to speed up or slow the build.

Real-world uses

Common Use Cases

Scroll-revealed stat sections
Grow a bar chart of metrics exactly as the reader scrolls into your results or pricing section, so the numbers land with motion rather than sitting static.
Lightweight dashboard accents
A vector bar chart that reacts to scroll makes a tiny, crisp dashboard hero without pulling in a full charting library.
Landing-page results
Show growth, adoption, or performance figures building up as visitors scroll through a marketing narrative.
Report and case-study reveals
Animate key figures into place as each section of a report scrolls in, pairing every bar with its supporting copy.
Learn Lottie scale animation
A clear example of growing shapes with a base-aligned scale transform in a hand-built Lottie. Pair it with the Lottie scroll scrub ring.
Data-driven hero graphics
Feed real numbers into the HEIGHTS array to turn the chart into a live, scroll-reactive summary of your own data.

Got questions?

Frequently Asked Questions

Animating a rectangle height grows it from its centre in both directions, which looks wrong for a chart. Placing each bar so its body sits above a base-aligned group origin and animating only the vertical scale from 0 to 100 stretches the bar upward from the baseline, exactly like a real column filling. It also keeps the animation to a single property per bar, which is simpler and cheaper than animating both height and position.

Because lottie-web treats an animated keyframe with no i/o easing tangents as a hold keyframe — it never interpolates, so a scale keyframed 0 to 100 stays stuck at 0 and the bar never grows. The keyframe helper in this snippet attaches linear tangents to every keyframe. If you hand-edit a keyframe and a bar stops growing, missing tangents are the first thing to check.

Edit the HEIGHTS array — each value from 0 to 1 is a bar height as a fraction of the maximum — and change N to match the number of bars. The x positions, colours, and stagger all derive from the index, so they adapt automatically. For labels or axis ticks, add more shape layers positioned along the baseline, or overlay HTML text on top of the pinned stage.

play runs the animation on its internal clock, which is exactly what you do not want when scroll should control it. goToAndStop(frame, true) renders one specific still frame and never starts the timer — the second argument tells lottie-web the value is a frame number, not milliseconds. Multiplying scroll progress by totalFrames gives the frame to show, and fractional frames interpolate smoothly so the growth is continuous.

Yes. Click JSX for a React component, Vue for a Vue 3 SFC, Angular for a standalone component, or Tailwind for a React + Tailwind version. Call lottie.loadAnimation against a ref inside a mount effect, register the ScrollTrigger there, and on cleanup call anim.destroy() and kill the ScrollTrigger instance (or revert a gsap.context) so the SVG and scroll listener are released on unmount.