remeasure
Get position and size of the DOM element for any React Component
Table of contents
Usage
// ES2015; // CommonJSconst measure Measured = default; // old school scriptvar measure = windowRemeasuremeasure;var Measured = windowRemeasureMeasured;
As a decorator
@measureComponent { const height width = thisprops; return <div>I have access to my height and width through props!</div>; } const StatelessComponent = ;
As a component
You can use the component with function-rendering components one of three ways:
// using a children methodconst MyMeasuredComponent = { return <Measured height width> { return <div> My height is height and my width is width </div> ; } </Measured> ;}; // using a component methodconst MyMeasuredComponent = { return <Measured height width component= { return <div> My height is height and my width is width </div> ; } /> ;}; // using a render methodconst MyMeasuredComponent = { return <Measured height width render= { return <div> My height is height and my width is width </div> ; } /> ;};
For performance reasons, it is recommended that you store the component as a separate method rather than create a method inline:
// using a render methodconst Render = { return <div> My height is height and my width is width </div> ;}; const MyMeasuredComponent = { return <Measured height width render=Render />;};
Measurements
The following properties are available for measurement:
bottom: Number clientLeft: Number clientHeight: Number clientWidth: Number clientTop: Number height: Number left: Number naturalHeight: Number naturalWidth: Number offsetHeight: Number offsetLeft: Number offsetTop: Number offsetWidth: Number scrollHeight: Number scrollLeft: Number scrollTop: Number scrollWidth: Number right: Number top: Number width: Number
The bottom
, left
, right
, and top
properties are what you would expect from the result of element.getBoundingClientRect()
. naturalHeight
and naturalWidth
are properties that are native to img
elements, and for all non-img
elements they are coalesced with scrollHeight
and scrollWidth
, respectively.
These properties are retrieved on mount, but will also automatically update if the element is resized thanks to ResizeObserver. Please note that elements that do not support content (such as img
) are not supported by this resize listener because there is no content box to observe. If you need to support those elements, simply create a higher-order component that wraps that element in a div
and decorate that component.
Advanced usage
keys
(Array<string>|string)
The keys to listen for changes to. If not specified, all possible keys will be measured.
Examples:
; // pass a string value for a single propertyconst measureOnlyOffsetWidth = ; const MyStatelessComponent = ; // or an array of string values for multiple properties@ { const top height = thisprops; return <div>Both the top and height props are injected</div>; }
You can apply the keys one of two ways on the Measure
component:
// either as individual boolean properties<Measured height> { return <div>I am height pixels in height</div> ; }</Measured> // or as the "keys" prop<Measured keys='height'> { return <div>I am height pixels in height</div> ; }</Measured>
Note that the properties will only be applied if they are set to true
(yes, you can actually toggle what properties are measured!).
options
Object
Allows customization of the measurements. Available options:
// value in milliseconds to debounce rerenders debounce: Number // sets namespace for values to be passed into props on namespace: String // should element rerender when resized renderOnResize: Boolean = true // should element rerender when the window is resized renderOnWindowResize: Boolean = false
Example usage with the decorator:
// use them alone@ { const height width = thisprops; return <div>The height and width props will not update with resizes</div>; } // or you can use them with keysconst MyStatelessComponent = { return <div> You can still pass options when you want to specify keys as the second parameter </div> ;};
Example usage with the Measured
component:
<Measured debounce=500 namespace="measurements"> { return <div>My measurements: JSON</div>; }</Measured>
ref
Like any other component, you can access the Measured
component instance via the ref
, but when using the measure
decorator you will be accessing the Measured
HOC and not the original component. If you want to access the original component, it is available as the originalComponent
property on that ref
.
@measurewidth { return thisprops; } { return <div>Use getProps to get my props!</div>; }... { console; // Measured component console; // Foo component console; // {bar: 'bar'} } { <Foo ref= { thisfoo = component; } bar="bar" /> }
Convenience methods
For each key that is measured, a convenience function exists on the measure
decorator. Example:
@measurewidth { const width = thisprops; return <div>I have width of width</div>; }
Caveats
A couple things to keep in mind when using remeasure
:
Void tags cannot detect element resize
If children on a tag are considered invalid HTML (such as for <input/>
, <img/>
, etc), then the internal element resize detector cannot work. The easy solution to this is to update the component via props (on update, a recalculation of values is triggered).
Components may render twice on update
If you perform an update to the component props
or state
that also happens to change its dimensions, the component will update twice, once for the changes to props
/ state
, and again for the changes to its dimensions. This is because the component needs to render in the DOM before updated values can be calculated.
Support
remeasure
has been tested and confirmed to work on the following browsers:
- Chrome
- Firefox
- Opera
- Edge
- IE9+
remeasure
also works with universal / isomorphic applications.
Development
Standard stuff, clone the repo and npm i
to get the dependencies. npm scripts available:
build
=> builds the distributed JS withNODE_ENV=development
and with sourcemapsbuild-minified
=> builds the distributed JS withNODE_ENV=production
and minifiedcompile-for-publish
=> runs thelint
,test
,transpile
,dist
scriptsdev
=> runs the webpack dev server for the playgrounddist
=> runs thebuild
andbuild-minified
lint
=> runs ESLint against files in thesrc
folderprepublish
=> if in publish, runscompile-for-publish
test
=> run ava with NODE_ENV=testtest:watch
=> runstest
but with persistent watchertranspile
=> runs Babel against files insrc
to files inlib