Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork20
😎 📏 React hook to measure an element's size and handle responsive components.
License
wellyshen/react-cool-dimensions
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
A Reacthook that measure an element's size and handleresponsive components with highly-performant way, usingResizeObserver. Try it you will 👍🏻 it!
❤️ it? ⭐️ it onGitHub orTweet about it.
⚡️ Try yourself:https://react-cool-dimensions.netlify.app
- 🚀 Measures element's size with highly-performant way, usingResizeObserver.
- 🎣 Easy to use, based on Reacthook.
- 🍰 Easy to handleresponsive components, provides an alternative solution to thecontainer queries problem.
- 📦 Supportsborder-box size measurement.
- 🕹 Supportsconditionally updating state.
- 🎛 Super flexibleAPI design to cover most cases for you.
- 📜 SupportsTypeScript type definition.
- 🗄️ Server-side rendering compatibility.
- 🦔 Tiny size (~ 1kB gzipped). No external dependencies, aside for the
react.
To usereact-cool-dimensions, you must usereact@16.8.0 or greater which includes hooks.
This package is distributed vianpm.
$ yarn add react-cool-dimensions# or$ npm install --save react-cool-dimensionsreact-cool-dimensions has a flexibleAPI design, it can cover simple to complex use cases for you. Here are some examples to show you how does it work.
⚠️ Most modern browsers support ResizeObserver natively. You can also usepolyfill for full browser support.
To report the size of an element by thewidth andheight states.
importuseDimensionsfrom"react-cool-dimensions";constApp=()=>{const{ observe, unobserve, width, height, entry}=useDimensions({onResize:({ observe, unobserve, width, height, entry})=>{// Triggered whenever the size of the target is changed...unobserve();// To stop observing the current target elementobserve();// To re-start observing the current target element},});return(<divref={observe}> Hi! My width is{width}px and height is{height}px</div>);};
💡 You don't have to call
unobservewhen the component is unmounted, this hook will handle it for you.
We havemedia queries but those are based on the browser viewport not individual elements. In some cases, we'd like to style components based on the width of a containing element rather than the browser viewport. To meet this demand there's aproposal forcontainer queries, but it still doesn't exist today...
No worries,react-cool-dimensions provides an alternative solution for us! We can activate theresponsive mode by thebreakpoints option. It's a width-based solution, once it's activated we can easily apply different styles to a component according to thecurrentBreakpoint state. The overall concept as below.
If you wish to update the state on the breakpoints changed, you can set theupdateOnBreakpointChange option totrue.
importuseDimensionsfrom"react-cool-dimensions";constCard=()=>{const{ observe, currentBreakpoint}=useDimensions({// The "currentBreakpoint" will be the object key based on the target's width// for instance, 0px - 319px (currentBreakpoint = XS), 320px - 479px (currentBreakpoint = SM) and so onbreakpoints:{XS:0,SM:320,MD:480,LG:640},// Will only update the state on breakpoint changed, default is falseupdateOnBreakpointChange:true,onResize:({ currentBreakpoint})=>{// Now the event callback will be triggered when breakpoint is changed// we can also access the "currentBreakpoint" here},});return(<divclass={`card${currentBreakpoint}`}ref={observe}><divclass="card-header">I'm 😎</div><divclass="card-body">I'm 👕</div><divclass="card-footer">I'm 👟</div></div>);};
Note: If the
breakpointsoption isn't set or there's no the defined breakpoint (object key) for a range of width. ThecurrentBreakpointwill be empty string.
You can use theshouldUpdate option to conditionally update the state to reduce unnecessary re-renders as below.
constreturnObj=useDimensions({shouldUpdate:({ currentBreakpoint, width, height, entry})=>{// Will only update the state when the target element's width greater than 300pxreturnstate.width>300;},});
Note: When
updateOnBreakpointChangeandshouldUpdateare used at the same time,shouldUpdatehas a higher priority.
By default, the hook reports thewidth andheight based on thecontent rectangle of the target element. We can include the padding and border for measuring by theuseBorderBoxSize option. Please note, thewidth andheight states are rely on theResizeObserverEntry.borderBoxSize butit hasn't widely implemented by browsers therefore we need to usepolyfill for this feature.
importuseDimensionsfrom"react-cool-dimensions";import{ResizeObserver}from"@juggle/resize-observer";constApp=()=>{const{ observe, width, height}=useDimensions({useBorderBoxSize:true,// Tell the hook to measure based on the border-box size, default is falsepolyfill:ResizeObserver,// Use polyfill to make this feature works on more browsers});return(<divstyle={{width:"100px",height:"100px",padding:"10px",border:"5px solid grey",}}ref={observe}>{/* Now the width and height will be: 100px + 10px + 5px = 115px */} Hi! My width is{width}px and height is{height}px</div>);};
You can share aref as follows:
import{useRef}from"react";importuseDimensionsfrom"react-cool-dimensions";constApp=()=>{constref=useRef();const{ observe}=useDimensions();return(<divref={(el)=>{observe(el);// Set the target element for measuringref.current=el;// Share the element for other purposes}}/>);};
TheonResize event will be triggered whenever the size of the target element is changed. We can reduce the frequency of the event callback by activating theresponsive mode or implementing our own throttled/debounced function as below. Note that in order to throttle/debounce the function correctly, it will need to be memorized else it will be recreated on every render call.
import{useMemo}from"react";import_from"lodash";constreturnObj=useDimensions({onResize:useMemo(()=>_.throttle(()=>{// Triggered once per every 500 milliseconds},500),[]),});
This hook supportsTypeScript, you can tell the hook what type of element you are going to observe through thegeneric type:
constApp=()=>{const{ observe}=useDimensions<HTMLDivElement>();return<divref={observe}/>;};
💡 For more available types, pleasecheck it out.
constreturnObj=useDimensions(options?:object);
It's returned with the following properties.
| Key | Type | Default | Description |
|---|---|---|---|
observe | function | To set a target element for measuring or re-start observing the current target element. | |
unobserve | function | To stop observing the current target element. | |
width | number or null | null | The width of the target element in pixel. Null while target has not mounted. |
height | number or null | null | The height of the target element in pixel. Null while target has not mounted.Z |
currentBreakpoint | string | Indicates the current breakpoint of theresponsive components. | |
entry | object | TheResizeObserverEntry of the target element. |
Theoptions provides the following configurations and event callback for you.
| Key | Type | Default | Description |
|---|---|---|---|
breakpoints | object | Activates the responsive mode forresponsive components orperformance optimization. | |
updateOnBreakpointChange | boolean | false | Tells the hook to update the state on breakpoint changed. |
useBorderBoxSize | boolean | false | Tells the hook tomeasure the target element based on the border-box size. |
shouldUpdate | function | Tells the hook toconditionally update the state. | |
onResize | function | It's invoked whenever the size of the target element is changed. But inresponsive mode, it's invoked based on the changing of the breakpoint rather than the size. | |
polyfill | ResizeObserver | It's used forinjecting a polyfill. |
ResizeObserver has good support amongst browsers, but it's not universal. You'll need to use polyfill for browsers that don't support it. Polyfills is something you should do consciously at the application level. Thereforereact-cool-dimensions doesn't include it.
We recommend using@juggle/resize-observer:
$ yarn add @juggle/resize-observer# or$ npm install --save @juggle/resize-observerThen inject it by thepolyfill option:
import{ResizeObserver}from"@juggle/resize-observer";const{ width, height}=useDimensions(ref,{polyfill:ResizeObserver});
Or pollute thewindow object:
import{ResizeObserver,ResizeObserverEntry}from"@juggle/resize-observer";if(!("ResizeObserver"inwindow)){window.ResizeObserver=ResizeObserver;// Only use it when you have this trouble: https://github.com/wellyshen/react-cool-dimensions/issues/45// window.ResizeObserverEntry = ResizeObserverEntry;}
You could use dynamic imports to only load the file when the polyfill is required:
(async()=>{if(!("ResizeObserver"inwindow)){constmodule=awaitimport("@juggle/resize-observer");window.ResizeObserver=module.ResizeObserver;// Only use it when you have this trouble: https://github.com/wellyshen/react-cool-dimensions/issues/45// window.ResizeObserverEntry = module.ResizeObserverEntry;}})();
💡 If you have written any blog post or article about
react-cool-dimensions, please open a PR to add it here.
- Featured onReact Status #191.
Thanks goes to these wonderful people (emoji key):
Welly 💻📖🚧 | Runar Kristoffersen 📖💻🤔 | Ricardo Amaral 💻 | Cornelius 🐛 | Joseph Horton 📖 | sirkrisp 💻 |
This project follows theall-contributors specification. Contributions of any kind welcome!
About
😎 📏 React hook to measure an element's size and handle responsive components.
Topics
Resources
License
Code of conduct
Contributing
Security policy
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Sponsor this project
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Contributors8
Uh oh!
There was an error while loading.Please reload this page.
