{"id":20638903,"url":"https://github.com/merri/react-lazy","last_synced_at":"2025-06-27T15:05:58.249Z","repository":{"id":35514705,"uuid":"39785010","full_name":"Merri/react-lazy","owner":"Merri","description":"(Implemented before loading=\"lazy\" was a thing.) Universal lazy loader components using IntersectionObserver for React","archived":false,"fork":false,"pushed_at":"2022-12-09T21:34:54.000Z","size":2026,"stargazers_count":118,"open_issues_count":25,"forks_count":8,"subscribers_count":1,"default_branch":"v1","last_synced_at":"2025-06-27T15:02:13.417Z","etag":null,"topics":["lazy-load","lazy-loading","lazyload","react","react-component","react-components","reactjs"],"latest_commit_sha":null,"homepage":"https://merri.github.io/react-lazy/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Merri.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-27T16:23:28.000Z","updated_at":"2025-04-15T03:39:50.000Z","dependencies_parsed_at":"2023-01-15T22:45:16.072Z","dependency_job_id":null,"html_url":"https://github.com/Merri/react-lazy","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/Merri/react-lazy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Merri%2Freact-lazy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Merri%2Freact-lazy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Merri%2Freact-lazy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Merri%2Freact-lazy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Merri","download_url":"https://codeload.github.com/Merri/react-lazy/tar.gz/refs/heads/v1","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Merri%2Freact-lazy/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262279099,"owners_count":23286547,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lazy-load","lazy-loading","lazyload","react","react-component","react-components","reactjs"],"created_at":"2024-11-16T15:20:35.946Z","updated_at":"2025-06-27T15:05:58.200Z","avatar_url":"https://github.com/Merri.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# react-lazy\n[![Version](https://img.shields.io/npm/v/react-lazy.svg)](https://www.npmjs.com/package/react-lazy)\n[![Build Status](https://travis-ci.org/Merri/react-lazy.svg)](https://travis-ci.org/Merri/react-lazy)\n\n\u003e Lazy load your content without breaking the internet!\n\nSupports universal rendering including disabled JavaScript by using `noscript` elements that are also friendly to all\nsearch engines. Uses modern IntersectionObserver API using the excellent\n[@researchgate/react-intersection-observer](https://github.com/researchgate/react-intersection-observer).\n\nAlso optionally supports displaying the content on IE8 and earlier by adding conditional comments to skip `noscript`\nelements.\n\n[View lazy loading demo](https://merri.github.io/react-lazy/)\n\n```js\nnpm install react-lazy\n\nimport { Lazy } from 'react-lazy'\n// or\nimport { LazyGroup } from 'react-lazy'\n```\n\nYou also need to polyfill `intersection-observer`! Use polyfill.io or `require('intersection-observer')`. Check\n[Can I use](https://caniuse.com/#feat=intersectionobserver) for browser support status. `Map` and `Set` are also\nrequired, but these are required by React as well.\n\n\n----\n\n## Why `react-lazy`?\n\n1. Minimalistic and performant implementation with less dependencies than other solutions\n2. You can choose between ease-of-use (LazyGroup) and do-it-yourself (Lazy)\n3. The hard part of handling `noscript` is done for you\n\n\n----\n\n### Why lazy load content such as images?\n\nYou want to save your bandwidth and/or server load. As a side effect you may also gain some performance benefits on\nclient side, especially on mobile devices. However the main benefit (and main purpose) for you should always be the\nreduction of bandwidth/server load.\n\nLikely side effect of lazy loading is that user may see content flashing as it comes into view; sometimes with a lot of\ndelay as it depends on connectivity. You can make the experience less flickery by adding a transition when image is\nloaded (a bit harder to develop) or by giving `Lazy` a large cushion (500 pixels or more) to load image before it is\nactually in the viewport. Using both strategies together is recommended. You can test the experience on your own site by\ndropping mobile connection to slow 3G.\n\nChrome developer tools also has network throttling so you don't need to get yourself into a train to nowhere to test how\nwell or poorly your site works in high latency conditions. However it is also recommended you do get yourself into a\ntrain to nowhere as it does good for your mind and soul to abandon the hectic although convenient city lifestyle every\nonce in a while.\n\n\n----\n\n## Usage: `\u003cLazy /\u003e`\n\n```jsx\n// curly brackets are required\nimport { Lazy } from 'react-lazy'\n\n...\n\n    \u003cLazy component=\"a\" href=\"/\" className=\"image-link image-link--100px\" ltIE9\u003e\n        \u003cimg alt=\"My Lazy Loaded Image\" className=\"image-link__image\" src=\"my-lazy-loaded-image.png\" /\u003e\n    \u003c/Lazy\u003e\n```\n\n```html\n\u003c!-- server render and render before component is in viewport --\u003e\n\u003ca href=\"/\" class=\"image-link image-link--100px\"\u003e\n    \u003c!--[if IE 9]\u003e\u003c!--\u003e\u003cnoscript\u003e\u003c!--\u003c![endif]--\u003e\n        \u003cimg alt=\"My Lazy Loaded Image\" class=\"image-link__image\" src=\"my-lazy-loaded-image.png\" /\u003e\n    \u003c!--[if IE 9]\u003e\u003c!--\u003e\u003c/noscript\u003e\u003c!--\u003c![endif]--\u003e\n\u003c/a\u003e\n\n\u003c!-- client DOM after component is in viewport --\u003e\n\u003ca href=\"/\" class=\"image-link image-link--100px\"\u003e\n    \u003cimg alt=\"My Lazy Loaded Image\" class=\"image-link__image\" src=\"my-lazy-loaded-image.png\" /\u003e\n\u003c/a\u003e\n```\n\n\n----\n\n## Component introduction\n\nThere are two components: `\u003cLazy /\u003e` and `\u003cLazyGroup /\u003e`.\n\n**Lazy** provides basic functionality for lazy loading: it keeps render in `noscript` element until it has come into\nviewport and then simply swaps render. **Everything** inside the component is wrapped into `noscript`. As the component\nis quite simple and generic it doesn't support many other things that provide convenience; for example, with images you\nhave to write your own logic for handling `onError` and `onLoad` so that you can do things like trigger transitions as\nimages are loaded, or change what to render instead of the image if loading the image fails.\n\n**LazyGroup** extends `Lazy` functionality by wrapping only specified component types inside `noscript`. So only the\nspecified components like `img` or `iframe` elements are wrapped to `noscript`. Other elements are simply rendered\nas-is.\n\nThe wrappable components (`img`s and `iframe`s by default) are also always wrapped inside another component. This custom\ncomponent will receive information on whether loading the `img` or `iframe` has succeeded or failed, thus allowing a\nsingle place to control lifecycles as images or other content is loaded.\n\n\n## Shared features\n\nThese features are supported by both `\u003cLazy /\u003e` and `\u003cLazyGroup /\u003e`.\n\n\n### IntersectionObserver props\n\n- `viewport` (= `root` option)\n- `cushion` (= `rootMargin` option)\n- `threshold`\n\nThese props work like you would expect them to work with IntersectionObserver.\n\n\n### `clientOnly` prop\n\nDisables `noscript` element rendering, instead rendering no HTML for the contents in server side. This gives behavior\nsimilar to most other lazy loaders, which is why it is not enabled by default in `react-lazy`.\n\n\n### `ltIE9` prop\n\nRenders Internet Explorer 8 friendly syntax by adding conditional comments around `noscript`, effectively hiding\nexistance of the tag from IE8 and earlier. This allows for minimal legacy browser support, since it is highly unlikely\nanyone writes their JS to execute on IE8 anymore.\n\nEssentially this feature allows to render a visually non-broken page to users of legacy browsers, making it possible to\ngive minimally acceptable user experience to users of browsers that should be dead.\n\nThis means there is no lazy rendering on legacy browsers, images load immediately.\n\nThis prop has no effect if `clientOnly` is enabled.\n\n\n### `onLoad`\n\n- On `Lazy` triggers after removing `noscript` element.\n- On `LazyGroup` triggers after **all** wrapped child components `onLoad` or `onError` events have triggered.\n\n```jsx\n\u003cLazy onLoad={yourCustomFunction}\u003e...\u003c/Lazy\u003e\n```\n\n\n### `onViewport`\n\nTriggers before removing `noscript` elements. Given function receives IntersectionObserver event object.\n\n\n### `visible`\n\nAllows you to manually tell if the element is actually visible to the user or not.\n\n\n----\n\n## `\u003cLazyGroup /\u003e`\n\n`Lazy` works fine with single images, but sometimes you may want to have slightly more control or better performance\nwhen you know multiple images load at the same time (for example, a row of thumbnails). In this case it makes no sense\nto check each individual image's position in viewport when checking for just the container component will be good enough\n\u0026mdash; and also less for a browser to execute.\n\nYou can also use `Lazy` for multiple images, but there are some practical limitations such as the fact that everything\ninside `Lazy` is within `noscript` element, thus there is nothing rendered inside. `LazyGroup` solves this issue by\nrendering `noscript` only around specific wrapped elements (`img` and `iframe` by default). Also, further control is\ngiven with `childWrapper` component that will receive a set of props to make life easier.\n\nUse cases:\n\n1. You want all contained images/iframes to be transitioned at the exact same time after everything is loaded.\n2. You want to use the abstraction provided by `childWrapper` instead of writing custom logic.\n3. You want to have slightly better performance by only checking the container element's location relative to the view.\n\n\n### Usage\n\n```jsx\n// curly brackets are required\nimport { LazyGroup } from 'react-lazy'\n\nfunction ImageContainer({ childProps, children, isFailed, isLoaded, ...props }) {\n    return (\n        // usually the other props include `dangerouslySetInnerHtml` when rendering `noscript` element\n        \u003cdiv {...props}\u003e\n            {isFailed ? 'The image did not load :( ' + childProps.src : children}\n        \u003c/div\u003e\n    )\n}\n\n...\n\n    \u003cLazyGroup component=\"ul\" className=\"image-list\" childWrapper={ImageContainer}\u003e\n        {this.props.images.map((image, index) =\u003e\n            \u003cli key={index} className=\"image-list__item\"\u003e\n                \u003cimg {...image} /\u003e\n            \u003c/li\u003e\n        )}\n    \u003c/LazyGroup\u003e\n```\n\n### `childWrapper` lifecycle\n\n1. On server side render and before the `LazyGroup` container is in viewport in client `childWrapper` will receive\n`dangerouslySetInnerHtml` prop (thus rendering `noscript` element that contains the lazily loaded content).\n2. After coming into viewport `isFailed` and `isLoaded` are false. `childProps` also become available.\n3. `isFailed` is set to true when `img`'s or `iframe`'s `onError` event triggers. You can use `childProps` to decide\nwhat to render.\n4. `isLoaded` is set to true when `img`'s or `iframe`'s `onLoad` event triggers.\n\n\n### `childrenToWrap`\n\nUse this array to decide which components are wrapped by `childWrapper`. Default value: `['iframe', 'img']`\n\n**Note!** The components **must** support `onError` and `onLoad` events as these are used to detect loading.\n\n\n----\n\n## Other components\n\nYou can see these components via React developer tools, but as of 1.0.2 they have not been exposed.\n\n\n### `DefaultWrapper`\n\nThis is the `childWrapper` used to render `LazyGroup`'s wrapped childs if no custom wrapper is given. The wrapper is a\nsimple div with a `className` of `react-lazy-wrapper`. BEM convention is used to tell about the lifecycle:\n\n1. `react-lazy-wrapper--placeholder` is set on server render and client render before `LazyGroup` is in viewport.\n2. `react-lazy-wrapper--loading` is set once `LazyGroup` is in viewport.\n3. `react-lazy-wrapper--failed` is set if lazy loaded component's `onError` event has triggered.\n4. `react-lazy-wrapper--loaded` is set if lazy loaded component's `onLoad` event has triggered.\n\n\n### `LazyChild`\n\nThis is the component used by `LazyGroup` to handle rendering of the wrapped child components. It manages the `onLoad` /\n`onError` handling. It takes two props: `callback` and `wrapper`. `callback` is called by `LazyChild` once loading\nresult has been resolved. `wrapper` is the component rendered around wrapped child element.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmerri%2Freact-lazy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmerri%2Freact-lazy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmerri%2Freact-lazy/lists"}