The CSS Typed Object Model (Typed OM) is a modern, object-oriented way to read and write CSS values via JavaScript. It replaces stringly-typed CSS with actual typed objects, making code safer, faster, and easier to reason about.
This post covers what Typed OM is, why it matters, what you can do with it today, and how it compares to traditional DOM/CSSOM approaches.
Why Typed OM?
 Historically, JavaScript interacts with CSS in two main ways:
- element.style and getComputedStyle return and accept strings
- Parsing and serializing CSS is manual and error-prone
Typed OM addresses this by:
- Providing typed value objects (e.g., CSSUnitValue, CSSMathSum)
- Allowing unit-aware arithmetic and conversions
- Avoiding string parsing/concatenation for most operations
- Reducing layout-thrashing pitfalls when measuring and updating styles
 The result: fewer bugs from unit mismatches, clearer intent, and potential performance wins.
Practical Use Cases
- Safer style updates: Avoid concatenating "px" or accidentally passing a number where a string is expected.
- Responsive calculations: Use CSSMathValue and clamp/min/max for dynamic sizing logic.
- Complex transforms: Build transforms from objects, not strings.
- Parsing user input: Convert input strings into typed values and validate units programmatically.
Performance Considerations
- Don’t over-allocate objects in tight loops. Reuse where possible.
- Batch reads and writes to avoid layout thrash (e.g., read via computedStyleMap, then write via attributeStyleMap).
- Measure: Always profile in target browsers.
Tips and Gotchas
- Property names are in their CSS hyphen-case when used with StylePropertyMap (e.g., 'background-color', not backgroundColor).
- Some shorthand properties aren’t fully decomposed across browsers; test get/set semantics.
- Computed style maps return computed values, which may be resolved into absolute units (e.g., rem → px).
- Be mindful that not all CSS properties have typed representations yet. In those cases, you’ll often get CSSKeywordValue or strings.
When to Use Typed OM
- You’re building component libraries or design systems that manipulate styles programmatically.
- You need precise, unit-safe arithmetic on CSS values.
- You want to avoid string parsing/formatting bugs and improve code clarity.
CSS Typed OM API Demo
CSS Typed OM API Demo
Open the browser console to see the typed CSS objects. Click the button to change the box's properties.
/* Basic body styling for clarity */
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
padding: 2em;
line-height: 1.6;
}
/* The box we will be manipulating with the Typed OM API */
.box {
width: 150px;
height: 150px;
background-color: steelblue;
opacity: 0.5;
/* We add transitions to make the changes visually smooth for the demo */
transition: width 0.5s ease-in-out,
opacity 0.5s ease-in-out,
transform 0.5s ease-in-out;
}
// Wait for the DOM to be fully loaded before running the script
document.addEventListener('DOMContentLoaded', () => {
// Get references to the DOM elements we'll be working with
const box = document.querySelector('.box');
const changeBtn = document.getElementById('changeBtn');
// --- DEMO 1: Reading CSS Properties with Typed OM ---
// Get the "computed style map" for the element. This is the entry point to the Typed OM.
// It's like window.getComputedStyle(), but returns typed objects instead of strings.
const styleMap = box.computedStyleMap();
// Let's get the 'width' property
const width = styleMap.get('width');
// Log the result to the console.
// Notice it's a CSSUnitValue object, not a string like "150px".
// This allows for easier and faster manipulation.
console.log('--- Reading Initial Styles ---');
console.log("The 'width' property is an object:", width);
console.log(`Value: ${width.value}, Unit: ${width.unit}`);
// Let's also get the opacity
const opacity = styleMap.get('opacity');
console.log("The 'opacity' property is an object:", opacity);
console.log(`Value: ${opacity.value}, Unit: ${opacity.unit}`); // CSSMathSum has a different structure
// --- DEMO 2: Manipulating and Writing CSS Properties ---
// Add a click event listener to the button to trigger changes
changeBtn.addEventListener('click', () => {
console.log('\n--- Button Clicked: Updating Styles ---');
// Get the current style map again inside the handler
const currentStyles = box.computedStyleMap();
// ** Manipulate Width **
// We can perform math directly on the .value property
const currentWidth = currentStyles.get('width');
const newWidthValue = currentWidth.value + 50;
// ** Manipulate Opacity **
const currentOpacity = currentStyles.get('opacity');
const newOpacityValue = currentOpacity.value * 1.5; // Make it more opaque
// To set styles, we use the 'attributeStyleMap'. This corresponds to the element's 'style' attribute.
// We use factory functions like CSS.px() and CSS.number() to create the correct typed objects.
box.attributeStyleMap.set('width', CSS.px(newWidthValue));
box.attributeStyleMap.set('opacity', CSS.number(newOpacityValue));
// You can also set properties that weren't there before, like 'transform'
box.attributeStyleMap.set(
'transform',
new CSSTransformValue([
new CSSTranslate(CSS.px(20), CSS.px(20)),
new CSSRotate(CSS.deg(45))
])
);
console.log(`Set width to: ${newWidthValue}px`);
console.log(`Set opacity to: ${newOpacityValue}`);
console.log('Set a new transform property.');
});
});
Summary
The CSS Typed Object Model modernizes JS–CSS interaction with:
- Typed values instead of fragile strings
- Unit-aware math and composition
- Better readability and potential performance gains
Adopt it progressively: check support, lean on Typed OM for complex style logic, and fall back to traditional APIs where necessary. As browser implementations mature, expect Typed OM to become the ergonomic and robust default for programmatic styling.