Skip to content

Instantly share code, notes, and snippets.

@mrclay
Last active May 19, 2026 16:39
Show Gist options
  • Select an option

  • Save mrclay/6620bab25c8553ca9be9f14d4b283932 to your computer and use it in GitHub Desktop.

Select an option

Save mrclay/6620bab25c8553ca9be9f14d4b283932 to your computer and use it in GitHub Desktop.
React/web components to measure available inline width
(() => {
/**
* Measures the available inline width.
*
* This example will show the width of the following P element:
*
* <div class="constrain">
* <measure-width></measure-width>
* <p>...</p>
* </div>
*/
class MeasureWidthElement extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
this._observer = null;
this._onResize = () => this.update();
}
connectedCallback() {
this.update();
window.addEventListener("resize", this._onResize);
this._observer = new ResizeObserver(() => this.update());
this._observer.observe(this);
}
disconnectedCallback() {
window.removeEventListener("resize", this._onResize);
if (this._observer) {
this._observer.disconnect();
this._observer = null;
}
}
update() {
const width = this.getBoundingClientRect().width;
const [whole, decimal] = String(Math.round(width * 1000) / 1000).split(
".",
);
const rest = decimal ? `.${decimal}` : "";
const style = `
:host {
background-color: #fff;
background-image: linear-gradient(to bottom, #ccc, #ccc);
background-size: 100% 1px;
background-position: center;
background-repeat: no-repeat;
border-inline: 1px solid #ccc;
border-block: 5px solid transparent;
color: #000;
display: block;
font: 14px/17px system-ui, sans-serif;
text-align: center;
}
span[a] {
display: inline-block;
background: #fff;
padding: 0 4px;
}
span[b] {
opacity: 0.5;
}
`;
this.shadowRoot.innerHTML = `
<style>${style}</style>
<span a>${whole}<span b>${rest}</span></span>
`;
}
}
if (!customElements.get("measure-width")) {
customElements.define("measure-width", MeasureWidthElement);
}
})();
import React, { useState, useRef, useLayoutEffect } from 'react';
/**
* Measures the available inline width.
*
* This example will show the width of the following P element:
*
* <div class="constrain">
* <MeasureWidth />
* <p>...</p>
* </div>
*/
function MeasureWidth() {
const [width, setWidth] = useState(0);
const rulerRef = useRef<HTMLDivElement>(null);
useLayoutEffect(() => {
const element = rulerRef.current;
if (!element) {
return;
}
const update = () => {
const rect = element.getBoundingClientRect();
setWidth(rect.width);
};
// Initial calculation
update();
const observer = new ResizeObserver(update);
observer.observe(element);
// eslint-disable-next-line consistent-return
return () => {
observer.disconnect();
};
}, []);
const widthString = String(Math.round(width * 1000) / 1000);
const [whole, decimal] = widthString.split('.');
const rest = decimal ? `.${decimal}` : '';
const styles: Record<string, React.CSSProperties> = {
container: {
backgroundColor: '#fff',
backgroundImage: 'linear-gradient(to bottom, #ccc, #ccc)',
backgroundSize: '100% 1px',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
borderInline: '1px solid #ccc',
borderBlock: '5px solid transparent',
color: '#000',
display: 'block',
font: '14px/17px system-ui, sans-serif',
textAlign: 'center',
width: '100%',
boxSizing: 'border-box',
},
spanA: {
display: 'inline-block',
background: '#fff',
padding: '0 4px',
},
spanB: {
opacity: 0.5,
},
};
return (
<div ref={rulerRef} style={styles.container}>
<span style={styles.spanA}>
{whole}
<span style={styles.spanB}>{rest}</span>
</span>
</div>
);
}
export default MeasureWidth;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment