v133 · css

Progress Bars

Progress bars styled entirely in CSS using attr(data-value type(<number>), 0) — no style="width:…" needed. Set the value in HTML via data-value="72"; CSS reads it as a number and uses it in calc() to drive the fill width.

Feature detection: checking…

The data-value attribute is a plain HTML attribute. CSS typed attr() interprets it as a <number> and feeds it into calc() — no JavaScript and no inline style needed.

Tasks — driven by data-value HTML attributes
CSS typed attr()
100%
Type-safe CSS
73%
Disk usage
48%
Memory usage
91%
Accessibility score
12%
Ratio bars — data-value / data-max via calc()
Storage: 340 / 500 MB
68%
Seats used: 7 / 10
70%
Live editor — adjust data-value without JavaScript
Value 65
Live bar
65%

Only the data-value HTML attribute is changed; CSS attr() reads the new number and CSS calc() updates the width — no inline style, no CSS variable, no JS style manipulation.

technique comparison

techniqueHTMLCSSJS needed?
Inline style style="width:72%" none Yes — must set inline style
CSS variable style="--p:72%" width: var(--p) Yes — must set CSS variable
Typed attr() (Chrome 133+) data-value="72" width: calc(attr(data-value type(<number>)) * 1%) No — pure CSS reads the data attribute
/* Typed attr() reads a data attribute as a CSS number */
.progress-fill {
  width: calc(attr(data-value type(), 0) * 1%);
  /* data-value="72" → width: 72% */
}

/* Ratio: attr() on two attributes */
.progress-fill-ratio {
  width: calc(
    attr(data-value type(), 0) /
    attr(data-max   type(), 100) * 100%
  );
  /* data-value="340" data-max="500" → width: 68% */
}

/* Colour semantics via data-status selector */
[data-status="danger"] .progress-fill { background: red; }

see also