{"slug": "introducing-css-typed-om-a-complete-and-wpt-tested-polyfill-for-css-typed-om", "title": "Introducing css-typed-om, a complete and WPT-tested polyfill for CSS Typed OM", "summary": "Developer Bramus Van Damme released css-typed-om, a complete, standalone, Web Platform Test-tested polyfill for the CSS Typed Object Model, installable via npm as css-typed-om. The polyfill patches window.CSS, Element.prototype.computedStyleMap, HTMLElement.prototype.attributeStyleMap and all CSS Typed OM classes, addressing Firefox's incomplete native implementation, which remains behind the layout.css.typed-om.enabled flag per Firefox bug 1278697, and missing CSSColorValue subclasses such as CSSRGB and CSSOKLCH. Van Damme said the spec's scope — a full CSS tokenizer, calc() expression simplifier, 2D/3D matrix math and WebIDL interface rules — had made a hand-written polyfill too large an undertaking until AI assistance made it feasible.", "body_md": "Being a big fan of the [CSS Typed OM](https://developer.mozilla.org/en-US/docs/Web/API/CSS_Typed_OM_API), I’ve wanted a proper polyfill for it for years. Just before my summer vacation back in July, with the help of Gemini/Antigravity, I finally built one: [`css-typed-om`](https://github.com/bramus/css-typed-om-polyfill).\n\n~\n\n### [#](#the-problem) Why CSS Typed OM? (And why a polyfill?)\n\nIf you’ve ever read or manipulated styles in JavaScript using `element.style` or `window.getComputedStyle()`, you know the pain of dealing with strings. Want to read an element’s `width` and add `20px` to it? You have to parse the string, strip the unit, convert it to a number, do the math, and concatenate it back into a string. Throw `calc()`, `transform` matrices, or modern color spaces into the mix, and string manipulation quickly falls apart.\n\n``` js\nconst styles = getComputedStyle($el);\nconst opacity = styles.getPropertyValue('opacity');\n\nconsole.log(opacity); // '0.2'\nconsole.log(typeof opacity); // String!?\n```\n\nThat’s where the [CSS Typed Object Model (CSS Typed OM)](https://developer.chrome.com/docs/css-ui/cssom) comes in. Instead of strings, it exposes CSS values as typed JavaScript objects — such as `CSSUnitValue`, `CSSMathSum`, `CSSTransformValue`, and `CSSKeywordValue` — through `element.attributeStyleMap`, `element.computedStyleMap()`, and unit factory functions like `CSS.px(20)`.\n\n``` js\nconst styles = $el.computedStyleMap();\nconst opacity = styles.get('opacity');\n\nconsole.log(opacity); // CSSUnitValue\nconsole.log(opacity.value); // 0.2\nconsole.log(opacity.unit); // 'number\n```\n\nHowever, browser support isn’t 100% uniform yet. While Chromium and Safari ship CSS Typed OM, Firefox’s native implementation is still a work in progress behind the `layout.css.typed-om.enabled` flag (see [Firefox bug 1278697](https://bugzil.la/1278697)). And even in browsers that do support Typed OM, some newer parts of the spec — like the `CSSColorValue` subclasses (`CSSRGB`, `CSSOKLCH`, etc.) — aren’t available everywhere yet.\n\n~\n\n### [#](#enter-css-typed-om) Enter `css-typed-om`\n\nBuilding a standalone CSS Typed OM polyfill has been sitting on my backlog for years — especially when seeing other projects like the *(partial)* [`scroll-timeline` polyfill](https://github.com/flackr/scroll-timeline) having to roll and bundle parts of the CSS Typed OM implementation themselves just to support unit values like `CSS.percent()` or `CSS.px()`.\n\nHowever, the [CSS Typed OM specification](https://drafts.css-houdini.org/css-typed-om-1/) is *huge*, covering everything from a full CSS tokenizer and `calc()` expression simplifier to 2D/3D matrix math and WebIDL interface rules. Writing all of that by hand was simply too big of an undertaking for a side project. But now, thanks to AI, that long-standing goal finally came within reach: meet [`css-typed-om`](https://github.com/bramus/css-typed-om-polyfill). Guided by the specification and the official Web Platform Tests, `css-typed-om` is a complete, standalone, and full tested polyfill that you can drop into any project. 🚀\n\n~\n\n### [#](#installation-and-usage) Installation & Usage\n\nYou can install the package from npm:\n\n```\nnpm install css-typed-om\n```\n\nDepending on your setup, you can use `css-typed-om` in two ways.\n\n~\n\n#### 1. As a Global Polyfill\n\nImport the package once at the entry point of your application to automatically patch `window.CSS`, `Element.prototype.computedStyleMap`, `HTMLElement.prototype.attributeStyleMap`, and all CSS Typed OM classes:\n\n``` js\nimport 'css-typed-om';\n\n// Read computed styles as typed objects\nconst element = document.querySelector('.my-element');\nconst width = element.computedStyleMap().get('width');\n\nconsole.log(width.value); // e.g., 100\nconsole.log(width.unit);  // e.g., 'px'\n\n// Set inline styles using CSS unit factories\nelement.attributeStyleMap.set('opacity', CSS.number(0.5));\nelement.attributeStyleMap.set('margin-top', CSS.px(20).add(CSS.em(2)));\n```\n\n💁♂️ Don’t use a bundler? There’s also an IIFE build available that you can drop straight into a page via a `<script src=\"https://unpkg.com/css-typed-om\"></script>` tag.\n\n~\n\n#### 2. As an Explicit ES Module\n\nIf you prefer importing the classes directly (for example in unit tests or modular libraries):\n\n``` js\nimport { CSSUnitValue, CSSKeywordValue } from 'css-typed-om';\n\nconst width = new CSSUnitValue(100, 'px');\nconst display = new CSSKeywordValue('block');\n```\n\n~\n\n### [#](#wpt-tested) Tested against Web Platform Tests (WPT)\n\nWhen building a polyfill for a spec as sprawling as CSS Typed OM, custom unit tests alone aren’t enough. There are hundreds of edge cases around `calc()` simplification, serialization order, out-of-range value clamping, shorthand properties, and WebIDL interface rules.\n\nTo make sure the polyfill behaves just like a native implementation, I wired the repository directly up to the official [Web Platform Tests (WPT)](https://github.com/web-platform-tests/wpt) suite. Running `npm run test:wpt` spins up headless Firefox (with its experimental native `layout.css.typed-om.enabled` flag explicitly disabled), injects the IIFE build of the polyfill, and runs all 400+ WPT test files in `/css/css-typed-om/`.\n\nAt the time of writing, the polyfill passes **12,479 out of 13,134** WPT subtests (~95%)! 🙂\n\n**🤔 Why not 100%?** To keep the bundle size small instead of shipping a 400KB+ database of every CSS property grammar in existence, the polyfill delegates per-property syntax validation to the host browser’s native CSS parser under the hood. That means if WPT tests a bleeding-edge CSS property or keyword that the host browser itself hasn’t implemented in CSS yet, the browser’s CSS parser rejects it — which is actually what you want in practice, since `element.style` and `getComputedStyle()` stay 100% in sync with what the browser supports. An example here is the recent rename of the `anchors-valid` keyword to `anchor-valid`, which Firefox 157 which I use for testing does not support.\n\nAdditionally, some tests — like those testing `currentcolor` (or `auto` / percentages on layout properties like `width`) via `computedStyleMap()` — can never pass in a userland polyfill. That’s because `computedStyleMap()` has to read from `window.getComputedStyle()`, which returns the resolved value (such as `rgb(0, 0, 0)`) instead of the keyword `currentcolor` — leaving the polyfill with no way to know that `currentcolor` was originally specified.\n\n~\n\n### [#](#acknowledgements) Acknowledgements & Links\n\nFirst of all, a shout-out to [Johannes Odland](https://github.com/johannesodland), who had PR’d some significant CSS Typed OM parts into the [`scroll-timeline` polyfill](https://github.com/flackr/scroll-timeline) back in the day. It’s his work that first sparked the idea of writing a full, standalone CSS Typed OM polyfill.\n\nA special shout-out and thank you goes to [Jonathan Neal](https://github.com/jonathantneal), who kindly handed over the `css-typed-om` package name on npm *(which previously housed the now-archived [`csstools/css-typed-om`](https://github.com/csstools/css-typed-om) project)*. Thanks, Jonathan! 🙌\n\n~\n\n### [#](#spread-the-word) Spread the word\n\nFeel free to reshare one of the following posts on social media to help spread the word:\n\n~\n\n**🔥 Like what you see? Want to stay in the loop? Here's how:**\n\nI can also be found on [𝕏 Twitter](https://x.com/bramus) and [🐘 Mastodon](https://front-end.social/@bramus) but only post there sporadically.", "url": "https://wpnews.pro/news/introducing-css-typed-om-a-complete-and-wpt-tested-polyfill-for-css-typed-om", "canonical_source": "https://www.bram.us/2026/10/13/introducing-css-typed-om-a-complete-and-wpt-tested-polyfill-for-css-typed-om/", "published_at": "2026-10-13 08:51:47+00:00", "updated_at": "2026-10-15 04:56:18.221398+00:00", "lang": "en", "topics": ["developer-tools", "artificial-intelligence"], "entities": ["Bramus Van Damme", "css-typed-om", "CSS Typed Object Model", "Firefox", "Chromium", "Safari", "Web Platform Tests", "Gemini"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/introducing-css-typed-om-a-complete-and-wpt-tested-polyfill-for-css-typed-om", "markdown": "https://wpnews.pro/news/introducing-css-typed-om-a-complete-and-wpt-tested-polyfill-for-css-typed-om.md", "text": "https://wpnews.pro/news/introducing-css-typed-om-a-complete-and-wpt-tested-polyfill-for-css-typed-om.txt", "jsonld": "https://wpnews.pro/news/introducing-css-typed-om-a-complete-and-wpt-tested-polyfill-for-css-typed-om.jsonld"}}