CSS Houdini: Paint API and Layout API
AI generated
CSS Houdini · Paint API · Layout API · Worklets
CSS Houdini: Paint API and Layout API
CSS.paintWorklet, registerPaint and custom layouts

CSS Houdini opens up the browser's rendering process to developers. Custom backgrounds, patterns and layout algorithms as worklets, usable directly in CSS. The most powerful, and also the most complex, approach to extending CSS.

15 min read CSS.paintWorklet · registerPaint · Layout API · Typed OM · Properties & Values API Chrome · Edge · Browser support in 2026

1. What is CSS Houdini?

CSS Houdini is not a single API but a collection of low-level APIs that make the browser's CSS engine extensible for developers. The name is a nod to Harry Houdini, the artist who escaped every constraint. The joke is fitting, because CSS Houdini frees developers from the constraint of having to wait for CSS features to be implemented: anyone who needs a new visual feature or a new layout algorithm no longer has to wait for browser vendors, they can implement it themselves as a worklet.

CSS Houdini covers several APIs: the Properties and Values API for typed custom properties, the Paint API for custom renderers, the Layout API for custom layout algorithms, the Typed Object Model (Typed OM) for typed CSS values in JavaScript, the Animation Worklet API for performant animations, and the Parser API for the CSS parser. Not all parts of CSS Houdini are equally mature or equally well supported, and that honest caveat is the part many articles gloss over.

The conceptual significance of CSS Houdini reaches beyond the individual APIs. It changes the relationship between the CSS specification and browser implementations. New CSS features such as custom properties, container queries and many others only became possible because browser vendors first built the internal architectures that CSS Houdini now exposes externally. In a sense, the APIs are the outward-facing side of the CSS engine's internal flexibility.

2. Understanding the CSS rendering pipeline

To understand CSS Houdini, you need to know the browser's rendering pipeline. The browser processes HTML and CSS in a defined order: parse, style, layout, paint, composite. Each phase has a clearly defined input and output. The style phase computes, from selectors and the cascade, which CSS properties apply to which element. The layout phase computes, from those properties, where each element sits on the screen. The paint phase renders the pixels. The composite phase combines multiple layers.

Before CSS Houdini, all of these phases were black boxes for developers. You could feed in CSS properties, but you could not influence the process itself. CSS Houdini opens specific entry points: the Paint API opens the paint phase, the Layout API the layout phase, the Animation Worklet API the composite phase. These entry points are implemented as worklets, small JavaScript contexts that run on the browser's rendering thread rather than the main JavaScript thread. That enables performant extensions without blocking the main JavaScript thread.


/* CSS Houdini: Properties and Values API */
/* Register a typed custom property, enables transitions and fallbacks */
@property --houdini-intensity {
  syntax: "<number>";
  inherits: false;
  initial-value: 0.5;
}

@property --houdini-color-primary {
  syntax: "<color>";
  inherits: true;
  initial-value: #7c3aed;
}

@property --stripe-angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 45deg;
}

/* Typed properties can be animated, unlike regular custom properties */
.element {
  --houdini-intensity: 0.2;
  background-image: paint(fancy-border);
  transition: --houdini-intensity 0.4s ease;
}

.element:hover {
  --houdini-intensity: 1.0; /* animatable because of the @property registration */
}

/* Use a paint worklet as a background */
.card-with-pattern {
  background-image: paint(diagonal-stripes);
  --stripe-angle: 30deg;
  --stripe-color: rgba(124, 58, 237, 0.15);
  --stripe-width: 4px;
}

3. Properties and Values API: typed custom properties

The Properties and Values API is the most widely supported part of CSS Houdini and, as of 2026, has landed in every modern browser. It solves a fundamental problem with regular CSS custom properties: to the browser, they are plain strings, it has no idea whether --my-color: #7c3aed is a color, a number or a length. As a result, custom properties cannot be animated, have no type checking, and no fallback value that can be interpolated correctly.

With @property from the Properties and Values API, you declare a custom property with a type, an inheritance behavior and an initial value. @property --rotation { syntax: "<angle>"; inherits: false; initial-value: 0deg; } registers a typed angle property. That property can be animated, has a sensible initial value, and tells the browser what range of values to expect. The CSS Houdini Properties and Values API is the gateway that turns custom properties from plain text substitutions into genuine CSS values.

The JavaScript alternative, CSS.registerProperty(), offers the same functionality programmatically. The @property syntax fits stylesheets, while CSS.registerProperty() fits JavaScript-based CSS libraries. Both approaches are part of the CSS Houdini Properties and Values API and behave identically.

4. The Paint API: CSS.paintWorklet and registerPaint

The Paint API is the visually most spectacular part of CSS Houdini. It lets you write custom paint worklets that can be used like native CSS backgrounds. The principle: a JavaScript worklet implements a paint() method that receives a Canvas 2D context to draw into. That worklet is registered via CSS.paintWorklet.addModule('worklet.js') and then used in CSS through background-image: paint(worklet-name).

What makes this special: CSS Houdini paint worklets run in an isolated worker thread that has access to the paint rendering context. They can read CSS custom properties and render based on their values. Changing a custom property value automatically triggers a new paint call. That makes fully parametrizable visual effects possible: a worklet that generates diagonally striped backgrounds with a configurable angle, color and width reacts to CSS variable changes without any JavaScript event listeners.


/* Paint worklet registration in JavaScript (worklet file) */
/* File: diagonal-stripes-worklet.js */

/* registerPaint is available in the worklet global scope */
registerPaint('diagonal-stripes', class {
  /* Declare which CSS custom properties this worklet reads */
  static get inputProperties() {
    return ['--stripe-color', '--stripe-width', '--stripe-angle'];
  }

  paint(ctx, size, properties) {
    /* Read CSS custom property values */
    const color = properties.get('--stripe-color').toString() || 'rgba(0,0,0,0.1)';
    const width = parseFloat(properties.get('--stripe-width')) || 4;

    ctx.strokeStyle = color;
    ctx.lineWidth = width;

    /* Draw diagonal lines across the element */
    const step = width * 3;
    for (let i = -size.height; i < size.width + size.height; i += step) {
      ctx.beginPath();
      ctx.moveTo(i, 0);
      ctx.lineTo(i + size.height, size.height);
      ctx.stroke();
    }
  }
});

/* In the main HTML file: register the worklet module */
/* CSS.paintWorklet.addModule('diagonal-stripes-worklet.js'); */

5. The Paint API in practice: patterns and backgrounds

The CSS Houdini Paint API enables visual effects that are impossible or extremely cumbersome with plain CSS: complex patterns, organic shapes, procedurally generated backgrounds, parametrizable gradients with non-linear curves. The most practical example is a parametrizable decorative background: a pattern rendered from CSS custom properties, whose complexity, color and density can be adjusted through a CSS variable or a media query.

Another example is custom borders and outlines. CSS border only offers simple straight lines and dashed or dotted variants. With the CSS Houdini Paint API you can draw arbitrary border shapes: jagged, wavy, with rounded corners on custom curves, or with a gradient running along the border. These effects were previously only achievable as an SVG background or via a JavaScript-driven canvas, never as a native CSS property.

One important limitation: paint worklets have no access to DOM information beyond custom properties. They see the element's dimensions (the size parameter), but no DOM siblings and no CSS properties other than the ones declared in inputProperties. That isolation is deliberate, it is what enables parallel rendering on the worker thread. Anyone who needs complex, data-driven visual effects combines CSS Houdini with custom properties set from JavaScript.

6. The Layout API: custom layout algorithms

The Layout API is the most powerful and most experimental component of CSS Houdini. It lets you implement complete layout algorithms as worklets, used in CSS through display: layout(my-algorithm). In theory, you could build new flexbox variants, masonry layouts, physics-based layouts or any other layout system this way, all without a browser update, purely as a JavaScript worklet.

A layout worklet implements two methods: intrinsicSizes() computes the container's intrinsic sizes based on its children. layout() receives information about the available size and the children's sizes and returns a position and size for each child. The worklet is a complete layout algorithm written in JavaScript that uses the browser's internal layout pipeline. Masonry, tiles arranged in a staggered grid like brickwork, was built as the reference implementation for the Layout API and remains its best-known example.


/* Layout API, CSS usage (when supported) */

/* Register the layout worklet in JavaScript first:
   CSS.layoutWorklet.addModule('masonry-layout.js');
   Then use it in CSS: */

.masonry-container {
  display: layout(masonry); /* custom layout algorithm */
  --masonry-gap: 1rem;
  --masonry-columns: 3;
}

/* Layout worklet definition (masonry-layout.js) */
/* registerLayout('masonry', class {
  static get inputProperties() {
    return ['--masonry-gap', '--masonry-columns'];
  }

  async intrinsicSizes(children, edges, styleMap) {
    // Return min/max content sizes
    const columns = parseInt(styleMap.get('--masonry-columns')) || 3;
    return { minContentSize: 0, maxContentSize: Infinity };
  }

  async layout(children, edges, constraints, styleMap) {
    const gap = parseFloat(styleMap.get('--masonry-gap')) || 16;
    const columns = parseInt(styleMap.get('--masonry-columns')) || 3;
    const colWidth = (constraints.fixedInlineSize - gap * (columns - 1)) / columns;
    const colHeights = new Array(columns).fill(0);

    const childFragments = await Promise.all(
      children.map(child => child.layoutNextFragment({ fixedInlineSize: colWidth }))
    );

    // Place each child in the shortest column
    for (const fragment of childFragments) {
      const col = colHeights.indexOf(Math.min(...colHeights));
      fragment.inlineOffset = col * (colWidth + gap);
      fragment.blockOffset = colHeights[col];
      colHeights[col] += fragment.blockSize + gap;
    }

    return { autoBlockSize: Math.max(...colHeights), childFragments };
  }
}); */

7. Typed Object Model: reading CSS values as types

The Typed Object Model (Typed OM) is the part of CSS Houdini that brings JavaScript developers the most everyday value, even though it is less spectacular than the Paint or Layout API. The classic problem: element.style.width returns a string like "150px". Every calculation requires manual parsing, unit conversion and string concatenation. The Typed OM instead returns typed objects: element.computedStyleMap().get('width') returns a CSSUnitValue object with a separate value and unit.

With the Typed OM, CSS calculations in JavaScript become noticeably more robust and readable. new CSSUnitValue(10, 'px').add(new CSSUnitValue(5, 'rem')) performs a type-safe CSS value addition. CSS Houdini Typed OM is available in Chrome and Edge, with limited scope in Safari and Firefox. For animations and CSS value interpolation the Typed OM is especially valuable: you work with real numbers instead of strings and avoid parsing errors entirely.

8. State of browser support in 2026

Browser support for CSS Houdini is fragmented in 2026, and that is the most honest statement one can make. The individual parts of the CSS Houdini platform sit at very different levels of maturity. The Properties and Values API (@property) is the most widely supported: Chrome, Edge, Safari and Firefox. The Paint API (CSS.paintWorklet) is available in Chrome and Edge, and only behind flags or not at all in Firefox and Safari. The Layout API has the least support: Chrome only, behind a flag.

For the CSS Houdini Paint API there are polyfills, such as the CSS Paint Polyfill, that recreate worklet functionality for browsers without native support, though with limitations in performance and not every Paint API feature covered. In practice this means: the Properties and Values API can be used in production today, the Paint API suits Chrome-first projects or works well as progressive enhancement, and the Layout API remains experimental in 2026. Adopting CSS Houdini in production requires a clear browser support strategy and progressive enhancement.

9. Houdini APIs at a glance

The various components of CSS Houdini differ substantially in maturity and practical value. A clear overview helps prioritize correctly for a given project.

API Function Browser support 2026 Production readiness
Properties & Values API Typed custom properties, @property Chrome, Edge, Safari, Firefox Production ready
Paint API CSS.paintWorklet, registerPaint Chrome, Edge (no Firefox/Safari) Progressive enhancement
Layout API CSS.layoutWorklet, registerLayout Chrome only (flag) Experimental
Typed OM Typed CSS values in JS Chrome, Edge, partially Safari Usable with caveats
Animation Worklet Performant scroll animations Chrome, Edge Limited

The practical recommendation for CSS Houdini in 2026: adopt @property right away, it has full browser support and a clear benefit through typed custom properties and animatable CSS variables. Use the Paint API for Chrome-first products or as a visual enhancement guarded with @supports (background: paint(x)). Keep an eye on the Layout API, but do not ship it in production code yet. Browser vendors are actively working on completing their CSS Houdini implementations, the state in 2026 is better than in 2024, but still not complete.

Mironsoft

Advanced CSS, Houdini implementations and modern browser APIs

Want to use CSS Houdini in your project?

We implement typed custom properties with @property, paint worklets for custom visual effects, and evaluate which Houdini APIs are production ready for your specific project.

@property migration

Type your custom properties, make them animatable, and secure them with initial values

Paint worklets

Custom patterns, borders and backgrounds as parametrizable CSS properties

Houdini assessment

Analysis of which Houdini APIs are production ready and worthwhile for your project in 2026

10. Summary

CSS Houdini is the extension platform for the browser's CSS rendering process. The Properties and Values API (@property) is production ready in 2026 and the recommended entry point: typed custom properties, animatable CSS variables and robust initial value handling are immediate benefits without browser support limitations. The Paint API can be used productively in Chrome-first projects and enables parametrizable background effects that plain CSS cannot achieve. The Layout API remains experimental and Chrome-only in 2026.

The strategic perspective: CSS Houdini is changing, over the long run, how CSS features get developed. New layout algorithms and visual effects can spread as worklets before they are ever added to the CSS specification. That accelerates innovation across the CSS ecosystem. Anyone who starts with CSS Houdini's production-ready parts today while keeping an eye on the experimental parts is well positioned for where CSS is headed over the next few years.

CSS Houdini: The essentials at a glance

@property (use now)

Typed custom properties with syntax, inheritance and an initial value. Full browser support in 2026. Enables animatable CSS variables.

Paint API (progressive enhancement)

CSS.paintWorklet.addModule() plus registerPaint() for custom backgrounds. Chrome/Edge. Guard with @supports.

Layout API (experimental)

CSS.layoutWorklet for custom layout algorithms. Chrome only, behind a flag. Not yet suitable for production.

Typed OM

Typed CSS values in JavaScript. computedStyleMap() instead of getComputedStyle(). Chrome/Edge, partially Safari.

11. FAQ: CSS Houdini

1What is CSS Houdini?
A collection of low-level APIs that make the browser's CSS rendering process extensible for developers. Paint API, Layout API, Properties & Values API, Typed OM.
2Which APIs are production ready in 2026?
@property, full browser support. Paint API, progressive enhancement on Chrome/Edge. Layout API, experimental.
3What does CSS.paintWorklet do?
Registers paint worklet modules. The worklet implements registerPaint() with a paint() method for Canvas 2D rendering. Usable in CSS via background-image: paint(name).
4What is @property?
CSS syntax of the Properties & Values API. Registers custom properties with a type, inheritance and an initial value. Makes custom properties animatable.
5Difference between Paint API and Canvas?
Paint worklets run on the rendering thread, have CSS property access but no DOM. Canvas runs on the main thread. Paint worklets perform better for CSS-integrated effects.
6Why is the Layout API experimental?
Chrome only, behind a flag. Firefox and Safari have not implemented it yet. Specification still evolving. No production use in 2026.
7Safeguarding paint worklets?
@supports (background: paint(x)) for progressive enhancement. Define a fallback outside the @supports block.
8What is the Typed Object Model?
CSS values as typed objects instead of strings. computedStyleMap().get('width') returns a CSSUnitValue. Makes the JS-CSS interaction more robust.
9Animate custom properties with @property?
Yes. Without @property they cannot be animated (the browser treats them as undefined strings). With a type declaration, they become fully animatable via CSS transition and animation.
10What is a worklet?
A lightweight JS context on the browser's rendering thread, not the main JS thread. Enables performant rendering extensions without blocking the main thread.