CSS Houdini APIs Reference

CSS Houdini worklet APIs — Paint, Layout, Animation — with registration syntax.

Reference for the CSS Houdini worklet and typed-OM APIs with registration syntax, input properties they read and current browser support status. It runs free in your browser on Gera Tools, with nothing uploaded.

Last updated Source: Gera Tools

What is CSS Houdini?

Houdini is a set of low-level APIs that expose parts of the CSS engine to JavaScript. They let developers extend CSS — registering custom paint logic, typed custom properties, and layout — instead of waiting for new CSS features to be standardised and shipped.

Extending CSS with Houdini

CSS Houdini is a family of low-level APIs that open the browser’s styling and layout engine to JavaScript. Instead of waiting for a new CSS feature to be specified and shipped, you can register custom paint routines, give custom properties real types, and (where supported) drive layout and animation from worklets. This reference lists the main Houdini APIs with their registration syntax, the inputs they consume, and how widely each is supported.

How it works

Most Houdini code runs in a worklet — a lightweight, isolated script context loaded with addModule. Inside it you register a class:

// paint.js — loaded with CSS.paintWorklet.addModule('paint.js')
registerPaint('checker', class {
  static get inputProperties() { return ['--tile-size']; }
  paint(ctx, size, props) {
    const t = parseInt(props.get('--tile-size'), 10) || 16;
    for (let y = 0; y < size.height; y += t)
      for (let x = 0; x < size.width; x += t)
        if (((x / t) + (y / t)) % 2 === 0) ctx.fillRect(x, y, t, t);
  }
});

Typed custom properties come from the main thread:

CSS.registerProperty({
  name: '--tile-size', syntax: '<length>',
  inherits: false, initialValue: '16px',
});

The worklet reads declared inputProperties, so animating --tile-size re-runs the paint each frame.

API directory

APIRegistration callStatus
Paint WorkletCSS.paintWorklet.addModule()Production-ready in Chromium
Properties and ValuesCSS.registerProperty()Production-ready in Chromium
Typed OMRead via attributeStyleMapProduction-ready in Chromium
Layout WorkletCSS.layoutWorklet.addModule()Experimental; limited support
Animation WorkletCSS.animationWorklet.addModule()Experimental; limited support

Practical use: animating a typed custom property

Registering a custom property unlocks smooth CSS transitions and animations on values that are otherwise inert strings. For example, if you register --glow-size as a <length>:

CSS.registerProperty({
  name: '--glow-size',
  syntax: '<length>',
  inherits: false,
  initialValue: '0px',
});

You can now animate it in CSS:

.button {
  --glow-size: 0px;
  box-shadow: 0 0 var(--glow-size) blue;
  transition: --glow-size 300ms ease;
}

.button:hover {
  --glow-size: 20px;
}

Without registerProperty, transitioning --glow-size does nothing — the browser treats it as a string and does not know how to interpolate between 0px and 20px. With a registered <length> type, the transition works automatically.

Worklet isolation model

Worklets run in a separate thread from the main JavaScript context. They have no access to the DOM, the window object, or fetch. Data enters through inputProperties (a static list of custom property names the paint worklet will read) and inputArguments (values passed in the CSS function call like background: paint(name, 10px)). This isolation is intentional: it lets the browser run the paint callback on the compositor thread without risking main-thread blocking.

Tips and notes

  • Always feature-detect — if ('paintWorklet' in CSS) { ... } — and provide a CSS fallback.
  • A registered typed property (e.g. <color>) becomes animatable; plain untyped --vars cannot be smoothly transitioned.
  • Worklets are isolated: no DOM, no window. Pass data through input properties and arguments only.
  • Paint and Properties/Values are the production-ready pair today; treat Layout and Animation worklets as experimental.
  • The Typed OM (attributeStyleMap, CSSStyleValue) is usable standalone and removes brittle string parsing of CSS values.