The CSS Typed Object Model API (element.attributeStyleMap and element.computedStyleMap()) exposes CSS values as typed JavaScript objects — CSSUnitValue, CSSColorValue, CSSTransformValue — instead of raw strings. This eliminates the string-parsing overhead in animation loops, provides unit-aware arithmetic (CSS.px(10).add(CSS.rem(2))), and integrates with the Worklet-based Houdini painting pipeline.
Problem: Reading and animating CSS values in JavaScript requires parsing strings like '16px', '1.5rem', or 'calc(100% - 20px)' manually — there is no native API to work with CSS values as typed objects.
Solution: Use the CSS Typed Object Model API — element.computedStyleMap().get('font-size') returns a CSSUnitValue with numeric .value and string .unit. Use element.attributeStyleMap.set('opacity', CSS.number(0.5)) to set values without string concatenation. The Typed OM is also usable in Worklet contexts (Houdini Paint API).
The examples below read typed property values, perform unit-aware arithmetic for an animation loop, use CSSTransformValue to animate a card without string concatenation, and register a CSS custom property with a typed syntax via CSS.registerProperty().
// ── 1. Read CSS values as typed objects ──────────────────────────────────
const el = document.querySelector( '.card' );
// computedStyleMap: read final computed values
const styleMap = el.computedStyleMap();
const fontSize = styleMap.get( 'font-size' );
console.log( fontSize.value, fontSize.unit ); // 16, "px"
const padding = styleMap.getAll( 'padding-top' );
const paddingPx = padding[0].to( 'px' ).value; // converts rem → px
// attributeStyleMap: read/write inline styles as typed values
el.attributeStyleMap.set( 'opacity', CSS.number( 0.5 ) );
el.attributeStyleMap.set( 'width', CSS.percent( 100 ) );
el.attributeStyleMap.set( 'margin-top', CSS.px( 16 ) );
// ── 2. Unit-aware arithmetic ──────────────────────────────────────────────
const base = CSS.px( 100 );
const offset = CSS.px( 50 );
const total = base.add( offset ); // CSSUnitValue { value: 150, unit: 'px' }
// ── 3. Animation loop: translate a card without string concatenation ──────
const card = document.querySelector( '.wp-block-my-plugin-card' );
let pos = 0;
function animate() {
pos += 1;
// No string building — direct typed value
card.attributeStyleMap.set( 'transform',
new CSSTranslate( CSS.px( pos ), CSS.px( 0 ) )
);
if ( pos < 300 ) requestAnimationFrame( animate );
}
requestAnimationFrame( animate );
// ── 4. Register a typed custom property (Houdini Properties & Values API) ─
CSS.registerProperty( {
name: '--card-progress',
syntax: '', // only accepts % values
inherits: false,
initialValue: '0%',
} );
// Now --card-progress can be animated in CSS (browser knows it's a number, not a string)
// @keyframes can interpolate it properly
const style = document.createElement( 'style' );
style.textContent = `
@keyframes fill-progress {
from { --card-progress: 0%; }
to { --card-progress: 100%; }
}
.progress-bar {
animation: fill-progress 2s ease forwards;
width: var(--card-progress);
}
`;
document.head.appendChild( style );
NOTE: element.computedStyleMap() is not supported in Firefox (as of 2025 it is Chromium-only) — for cross-browser production code, use the standard getComputedStyle() with manual string parsing as a fallback, or feature-detect with if ('computedStyleMap' in Element.prototype) before calling the Typed OM API.