Data✨ Premium

Bar Chart Animated

Vertical HTML bar chart: each bar grows up from the bottom with a slight bounce, one after the other, when the chart scrolls into view.

CSSStagger

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Data has 28 effects, including 1 free. Explore the category →

3 usage examples

Daily attendance at a swimming pool, revealed when reaching “When to come?” — Bar Chart Animated example 1

① Daily attendance at a swimming pool, revealed when reaching “When to come?”

WhenThe opening-hours page of a public pool: the visitor scrolls past the banner, the “Entries per day” card comes into view and the seven bars rise one after the other, value on top. In the capture the page scrolls by itself to show that moment.
WhyVisitors want the quietest day: seven heights compared at a glance answer better than a table, and the growth draws the eye to the Wednesday dip right as they reach it.
Settingsdata-show-values, values from 110 to 390 (automatic maximum), --brc-height: 170px, --brc-bar-width: 30px, --brc-bg: transparent, five blue gradients in --brc-c1 to --brc-c5.
Seven-day sales mini chart at the end of each row, a potter's back office — Bar Chart Animated example 2

② Seven-day sales mini chart at the end of each row, a potter's back office

WhenThe list of pieces for sale in a ceramics studio: every row (photo, name, stock) ends with a 30 px tall chart, one per piece, with the total next to it. The five charts play together when the list opens.
WhyWithout reading numbers you spot the piece that sells at weekends and the one that has stalled; the small rise signals that the list has just been refreshed.
SettingsFive independent roots, --brc-height: 30px, --brc-bar-width: 9px, --brc-max-width: 104px, --brc-min-height: 0, M T W T F S S labels hidden on screen by the page CSS (still read out), terracotta gradients.
The week's steps shown after syncing the pedometer, walking club — Bar Chart Animated example 3

③ The week's steps shown after syncing the pedometer, walking club

WhenIn a walking club's member area, the “Your week” card stays empty until the pedometer is synced. The “Sync” button reveals the hidden panel: the chart comes into view and its bars rise with values in thousands of steps.
WhyThe growth works as a confirmation: the sync succeeded and here is the result, no extra message needed. Showing the panel is what starts the effect, no code to add.
Settingsdata-show-values, decimal values (6.2 to 12.8) written in the page format, --brc-height: 168px, --brc-bar-width: 26px, sea-green gradients; the panel is a plain hidden removed on click.

How it works

The data lives in the HTML: a ul.brc-chart list where each li.brc-item holds its value in data-value and its label in span.brc-label. On start-up the script adds a decorative .brc-track (aria-hidden) to every item, holding the .brc-bar, plus a .brc-val text with the formatted value. A bar's height is value ÷ maximum: the maximum is the root's data-max attribute if present, otherwise the largest value in the list.

The chart does not play on page load but when it appears: an IntersectionObserver waits until at least 35% of the list is visible, reads the values again, then adds the brc-on class to the root. Each bar then goes from scaleY(0) to scaleY(1) in 1 s on a cubic-bezier(.34, 1.56, .64, 1) curve that overshoots slightly before settling, with a 0.1 s offset per bar. It only happens once.

With data-show-values on the root, a .brc-tip label sits above each bar and fades in right after it. Numbers are written with Intl.NumberFormat in the page language (nearest lang attribute): “1,240” on an English page, “1 240” on a French one. data-unit="%" gives a localised percentage; any other unit is appended after a non-breaking space.

The size follows the container: the list takes the available width up to --brc-max-width and the bars share the space without exceeding --brc-bar-width. The five original gradients (indigo, violet, magenta, pink, red) repeat every five items.

Accessibility

  • Screen readers: the list is announced as a real list (“Activity this week, list, 5 items”) and each item gives its label followed by its value, e.g. “Mon 60”. The value comes from the .brc-val text, present even when nothing is shown on screen. Remember to adapt the list's aria-label.
  • Reduced motion: under prefers-reduced-motion: reduce, bars and their values are drawn straight away at full height, with no growth and no fade.
  • Nothing to operate: the chart has no button or link, so it takes no keyboard focus and does not react to hover or touch.
  • Colour: the gradients carry no information, the value is always written; if you replace them, keep enough contrast with the background.

Browser compatibility

HTML, CSS (custom properties, transform, @keyframes) and a small script (IntersectionObserver, Intl.NumberFormat). Measured on 8 Nov 2026 in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): two independent copies on one page, the second waits until it is shown before playing, reduced motion, 390 px width, no errors.

Chrome 74+✓ Full (measured in Chromium 151)
Firefox 63+✓ Full (measured in Firefox 153)
Safari 12.1+✓ Measured in WebKit 26.5, not in real Safari
Edge 79+✓ Full (Chromium engine)
Safari iOS 12.2+✓ Not checked on a device
Chrome Android 74+✓ Full (Chromium engine)

Without IntersectionObserver, the bars play straight away on load. Without JavaScript only the labels show (heights are computed by the script).

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0225-root">
  <ul class="brc-chart" aria-label="Activity this week">
    <li class="brc-item" data-value="60"><span class="brc-label">Mon</span></li>
    <li class="brc-item" data-value="90"><span class="brc-label">Tue</span></li>
    <li class="brc-item" data-value="45"><span class="brc-label">Wed</span></li>
    <li class="brc-item" data-value="75"><span class="brc-label">Thu</span></li>
    <li class="brc-item" data-value="55"><span class="brc-label">Fri</span></li>
  </ul>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Values (HTML — data-value on each li.brc-item) 60, 90, 45, 75, 55 One positive number per item; add or remove li elements to change the number of bars. A negative or missing value counts as 0.
Scale maximum (HTML — data-max on the root) The largest value Set it (e.g. data-max="100") to compare several charts on the same scale.
Visible values (HTML — data-show-values on the root) Absent: values read by screen readers only Present: each bar carries its value above it.
Unit (HTML — data-unit on the root) None % gives a percentage in the page language's format; any other unit (km, h…) is appended after the number.
Bar colours (CSS — --brc-c1 to --brc-c5) Indigo, violet, magenta, pink, red gradients One background value per variable (colour or gradient); they repeat every five items.
Dimensions (CSS — --brc-height, --brc-max-width, --brc-bar-width, --brc-min-height) 160 px, 480 px, 48 px, 300 px Height of the bar area, maximum list width, maximum bar width, minimum root height (set 0 inside a small component).
Background and text (CSS — --brc-bg, --brc-text, --brc-value) #0a0a0f, 50% white, white On a light site: --brc-bg: transparent and dark text colours.

FAQ

No. While the tab is hidden (hidden or display: none) the list is not visible to the IntersectionObserver; the growth starts when the panel is shown, then never replays.
Values are read only once, when the chart appears, so a script can fill the data-value attributes before that. Afterwards, changing an attribute redraws nothing: replace the chart with a fresh copy of the HTML and run the script again.
Write the raw value with a dot (data-value="6.2", data-value="1240"): the script formats it for the page, up to one decimal, with a comma for thousands in English and a space in French.