v145 · Performance · JavaScript · demo

Blog Post

A realistic blog post template with four named containertiming sections — hero, body, code block, and sidebar. A PerformanceObserver watches for entries as each section finishes painting and builds a live timing waterfall, showing which content block painted first and how long each took.

Draft API: this page attempts the real containertiming attribute and PerformanceContainerTiming entries when PerformanceObserver advertises "container". Other browsers use a DOM-geometry simulation so the measurement workflow remains testable.

Replay the article load, toggle the ignored sidebar subtree, or probe observer support · the bar width represents each section's paint time relative to the total

Live Container Timing lab
Checking PerformanceObserver support…
Entries appear here after a replay or real observer callback.
Feature · Chrome 145
Container Timing gives LCP-style metrics for any element

The Largest Contentful Paint metric tells you when the biggest visible element on the page finishes painting. But what if you want to know when a specific product card, a news article's body, or a data dashboard renders — not just the page's biggest element?

Container Timing introduces the containertiming HTML attribute. Add it to any element and a PerformanceObserver receives a PerformanceContainerTiming entry the moment that section finishes its first contentful paint. The entry includes a renderTime, size, and the identifier you provided.

This makes it straightforward to measure things that LCP can't: "how long did our hero image block take?", "when was the sidebar populated?", or "did our above-the-fold content paint before the 1-second mark?"

// Set up the observer
const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    console.log(entry.identifier, entry.renderTime);
  }
});
observer.observe({ type: 'container', buffered: true });

// Mark sections with the HTML attribute:
// <section containertiming="hero"></section>
Container paint times
hero
pending…
body
pending…
code-block
pending…
sidebar
pending…
Observing…
// Container Timing draft API
// <section containertiming="hero">...</section>
// <aside containertiming-ignore>...</aside>

const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    // PerformanceContainerTiming entry:
    console.log({
      identifier: entry.identifier,       // "hero"
      entryType: entry.entryType,         // "container"
      startTime: entry.startTime,         // equals renderTime
      firstRenderTime: entry.firstRenderTime,
      size: entry.size,                   // painted area in CSS px²
      rootElement: entry.rootElement,
      lastPaintedElement: entry.lastPaintedElement
    });
  }
});

observer.observe({
  type: 'container',
  buffered: true  // capture already-painted sections
});

see also