{"id":19614318,"url":"https://github.com/fpapado/react-lazy-images","last_synced_at":"2025-04-12T23:29:21.183Z","repository":{"id":41817580,"uuid":"126631194","full_name":"fpapado/react-lazy-images","owner":"fpapado","description":"🖼️ 🛋️ Components and utilities for lazy image loading in React","archived":false,"fork":false,"pushed_at":"2023-04-23T21:03:26.000Z","size":3184,"stargazers_count":264,"open_issues_count":25,"forks_count":24,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-05-21T10:56:54.587Z","etag":null,"topics":["component","images","intersection-observer","lazy-loading","react"],"latest_commit_sha":null,"homepage":"https://fpapado.github.io/react-lazy-images","language":"TypeScript","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/fpapado.png","metadata":{"files":{"readme":"README.md","changelog":"changes.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-03-24T19:01:06.000Z","updated_at":"2024-06-18T12:41:04.637Z","dependencies_parsed_at":"2024-06-18T12:40:41.312Z","dependency_job_id":"4781a046-dbf9-413d-a49b-f039f6c67fab","html_url":"https://github.com/fpapado/react-lazy-images","commit_stats":{"total_commits":119,"total_committers":6,"mean_commits":"19.833333333333332","dds":0.07563025210084029,"last_synced_commit":"946e3d501788d22840d15aa752fbc08e0ea9e71e"},"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fpapado%2Freact-lazy-images","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fpapado%2Freact-lazy-images/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fpapado%2Freact-lazy-images/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fpapado%2Freact-lazy-images/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fpapado","download_url":"https://codeload.github.com/fpapado/react-lazy-images/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248646812,"owners_count":21139077,"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":["component","images","intersection-observer","lazy-loading","react"],"created_at":"2024-11-11T10:51:07.311Z","updated_at":"2025-04-12T23:29:21.164Z","avatar_url":"https://github.com/fpapado.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# React Lazy Images\n\n\u003e Components and utilities for lazy image loading in React.\n\n[![npm](https://img.shields.io/npm/v/react-lazy-images.svg)](https://www.npmjs.com/package/react-lazy-images)\n[![gzip size](http://img.badgesize.io/https://unpkg.com/react-lazy-images/dist/react-lazy-images.js?compression=gzip)](https://unpkg.com/react-lazy-images/dist/react-lazy-images.js)\n[![npm downloads](https://img.shields.io/npm/dm/react-lazy-images.svg)](https://www.npmjs.com/package/react-lazy-images)\n[![dependencies](https://david-dm.org/fpapado/react-lazy-images.svg)](https://david-dm.org/fpapado/react-lazy-images)\n\u003ca href=\"https://codesandbox.io/s/jnn9wjkj1w\"\u003e\n\u003cimg src=\"https://codesandbox.io/static/img/play-codesandbox.svg\" height=\"20px\"/\u003e\n\u003c/a\u003e\n\n## Table of Contents\n\n- [Features](#features)\n- [Install](#install)\n- [Motivation](#motivation)\n- [Usage](#usage)\n- [Examples](#examples)\n- [API Reference](#api-reference)\n- [Feedback](#feedback)\n- [Roadmap](#roadmap)\n- [Contributing](#contributing)\n- [Thanks](#thanks-and-inspiration)\n- [License](#license)\n\n## Features\n\n- Composable pieces, preloading images and handling failures.\n- Full presentational control for the caller (render props).\n- Modern, performant implementation, using [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) and providing [polyfill information](#polyfill-intersection-observer).\n- [Eager loading / Server-side rendering support](#eager-loading--server-side-rendering-ssr).\n- [Debounce / Delay](#debounce--delay); can wait for an image to be in the viewport for a set time, before loading.\n- Works with horizontal scrolling, supports background images.\n- [Fallbacks for SEO / when Javascript is disabled](#fallback-without-javascript).\n- Easy to understand source code. You should be able to fork and do your thing if desired.\n- Ample documentation to help you understand the problem, in addition to the solutions.\n\nWhat it does not do by itself:\n\n- Polyfill `IntersectionObserver`. Adding polyfills is something you should do consciously at the application level. See [Polyfilling IntersectionObserver](#polyfill-intersectionobserver) for how to do this.\n- Dictate the kind of placeholders displayed. There are many ways to do it; you can use a simple box with a background color, a low-resolution image, some gradient, etc.\n  In other words, this library focuses on loading the images once in view and supporting **loading patterns** around that.\n  The presentational patterns are yours to decide!\n  Fear not though, [we cover both patterns in the examples section](#examples).\n\n## Install\n\nThis package is distributed via [npm](https://www.npmjs.com/get-npm).\n\n```shell\n$ npm install --save react-lazy-images\n# or\n$ yarn add react-lazy-images\n```\n\nThen import according to your modules model and bundler, such as [Rollup](https://rollupjs.org/guide/en) and [Webpack](https://webpack.js.org/):\n\n```js\n// ES Modules\n// For all possible functions to import look at the documentation\nimport { LazyImage } from \"react-lazy-images\";\n\n/// CommonJS modules\nconst { LazyImage } = require(\"react-lazy-images\");\n```\n\nA [UMD](https://github.com/umdjs/umd) version is also available on [unpkg](https://unpkg.com/):\n\n```html\n\u003cscript src=\"https://unpkg.com/react-lazy-images/dist/react-lazy-images.umd.js\"\u003e\u003c/script\u003e\n```\n\n## Motivation\n\nBrowsers preload images; as soon as they encounter an `\u003cimg\u003e` tag with a valid `src`, they kick off the request for the image (they even do this before the HTML has been parsed).\nEven in cases where a certain image is not in the viewport, it will be requested.\nThis can have adverse effects for users, especially on mobile or metered connections.\n\nThis brings us to the basic premise of any Lazy Image Loading library:\n\n- Have a way to observe the visibility of the DOM elements\n- Prevent the browser from loading images directly\n- Once an image is in view, instruct the browser to load it and place it in the element\n\nIn vanilla JS, this means \"hiding\" the actual `src` in a `data-src` attribute, and using classes to indicate state, e.g. `.isLazyLoaded .lazyLoad`.\nOn initialisation, a script queries for these classes and attributes, keeps track of visibily, and swaps `data-src` with an actual `src`, kicking off the browser request process.\nIt can elect to preload the Image, and only swap once loaded.\n\nWith React, all this implicit state management is brought into one place, since you do not have to stash loading information in the DOM and pick it back up again.\nThis can potentially mean a nicer, more composable codebase, and it was one of the main design goals for this library.\n\nThe way to do this visibility tracking has for the most part been listening for events such as scroll.\nThis is synchronous by nature and [can have performance implications](https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video/#lazy_loading_images).\nIt also involves calling `getBoundingClientRect()` to calculate the interesection of the image with the viewport; this function causes relayout.\nThis was the motivation for browsers providing [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API).\nUsing this API is not specific to React; it just seems like a good fit for this task nowadays.\n\n## Usage\n\n### Quick Start\n\nIf you want to just dive in, do this:\n\n```jsx\nimport { LazyImage } from \"react-lazy-images\";\n\n\u003cLazyImage\n  src=\"/img/porto_buildings_large.jpg\"\n  alt=\"Buildings with tiled exteriors, lit by the sunset.\"\n  placeholder={({ imageProps, ref }) =\u003e (\n    \u003cimg ref={ref} src=\"/img/porto_buildings_lowres.jpg\" alt={imageProps.alt} /\u003e\n  )}\n  actual={({ imageProps }) =\u003e \u003cimg {...imageProps} /\u003e}\n/\u003e;\n```\n\n:warning: It is important that you pass on the ref in placeholder, otherwise the detection of the element intersecting is impossible. :warning:\n\nNote that while you can set the rendered components to be anything you want, you most likely want to use the same `src`, `srcSet` and `alt` attributes in an `\u003cimg\u003e` eventually.\nTo keep this consistent, and reduce repetition, the render callbacks pass those attributes back to you.\n\n[You can play around with this library on Codesandbox](https://codesandbox.io/s/jnn9wjkj1w).\n\nAdditionally, make sure you understand [how to polyfill IntersectionObserver](#polyfill-intersectionobserver) and [strategies for when JS is not available](#fallback-without-javascript).\n\nFrom then on:\n\n- If you want to learn more about the API and the problem space, read the rest of this section.\n- If you need more fine-grained rendering, [read about `LazyImageFull`](#more-control-with-lazyimagefull).\n- If you want to list the props, see the [API reference](#api-reference).\n\n### Customising what is displayed\n\nThe render prop pattern is used throughout in `LazyImage`.\nThe `LazyImage` component **handles the behaviour of tracking when the image is in view, but leaves the actual rendering up to the consumer**.\nThus, whether you want to display a simple `\u003cimg\u003e`, your own `\u003cImage\u003e`, or even wrapped elements, it is simple to do so:\n\n```jsx\n\u003cLazyImage\n  src=\"/img/porto_buildings_large.jpg\"\n  alt=\"Buildings with tiled exteriors, lit by the sunset.\"\n  // This is rendered first, notice how the src is different\n  placeholder={\n    ({imageProps, ref}) =\u003e\n      \u003cimg ref={ref} src=\"/img/porto_buildings_lowres.jpg\" alt={imageProps.alt} /\u003e\n  }\n  // This is rendered once in view; we use the src and alt above for consistency\n  actual={\n    ({imageProps}) =\u003e\n      \u003cimg {...imageProps} /\u003e\n  }\n/\u003e\n\n// Perhaps you want a container?\n\u003cLazyImage\n  src=\"/img/porto_buildings_large.jpg\"\n  alt=\"Buildings with tiled exteriors, lit by the sunset.\"\n  placeholder={\n    ({imageProps, ref}) =\u003e\n      \u003cdiv ref={ref} className={'LazyImage-Placeholder'}\u003e\n        \u003cimg src=\"/img/porto_buildings_lowres.jpg\" alt={imageProps.alt} /\u003e\n      \u003c/div\u003e\n  }\n  actual={\n    ({imageProps}) =\u003e\n      \u003cdiv className={'LazyImage-Actual'}\u003e\n        \u003cimg {...imageProps} /\u003e\n      \u003c/div\u003e\n  }\n/\u003e\n```\n\nThese props are there to instruct the component what to render in those places, and they take some useful information (in this case, a className) from the LazyImage.\n\n### More control with LazyImageFull\n\n`LazyImage` should work for most cases, but you might need more fine-grained rendering.\nOne use case would be doing animations with CSS transitions, where re-rendering the component (which `LazyImage` does) would not be sufficient.\nIn those cases, consider `LazyImageFull`:\n\n```jsx\nimport { LazyImageFull, ImageState } from \"react-lazy-images\";\n\n// Function as child\n// `src`, `alt` and `srcSet` are passed back to the render callback for convenience/consistency\n\u003cLazyImageFull src=\"/img/porto_buildings_large.jpg\"\u003e\n  {({ imageProps, imageState, ref }) =\u003e (\n    \u003cimg\n      {...imageProps}\n      ref={ref}\n      src={\n        imageState === ImageState.LoadSuccess\n          ? imageProps.src\n          : \"/img/porto_buildings_lowres.jpg\"\n      }\n      style={{ opacity: ImageState.LoadSuccess ? \"1\" : \"0.5\" }}\n    /\u003e\n  )}\n\u003c/LazyImageFull\u003e;\n```\n\nThis component takes a function as a child, which accepts `{src, srcSet, imageState}`.\nThe various image states are imported as `{ImageState}`, and you can conditionally render based on them.\n\nThis technique can give you more fine-grained rendering if needed, but can potentially be more verbose.\nAny of the presentational patterns presented that are possible with `LazyImage` are also possible with `LazyImageFull`.\n(The opposite is not necessarily true, or at least has more duplication).\n\nIn fact, if you check [`src/LazyImage.tsx`](./src/LazyImage.tsx), you will see that `LazyImage` is implemented in terms of `LazyImageFull`!\n\n### Load ahead and threshold\n\nFurther control over the Intersection Observer can be provided through the `observerProps` prop object:\n\n```jsx\nimport { LazyImage } from \"react-lazy-images\";\n\n\u003cLazyImage\n  src=\"/img/porto_buildings_large.jpg\"\n  alt=\"Buildings with tiled exteriors, lit by the sunset.\"\n  placeholder={/* the usual */}\n  actual={/* the usual */}\n  observerProps={{\n    rootMargin: \"100px 0\",\n    threshold: 0.3\n  }}\n/\u003e;\n```\n\n`rootMargin`: Margin around the window. This can have values similar to the CSS margin property, e.g. `\"10px 20px 30px 40px\"` (top, right, bottom, left) (defaulted to `\"50px 0px\"`)\nThis can provide control if you want to request your image a certain number of pixels ahead of where the user is scrolling.\n\n`threshold`: Number between 0 and 1 indicating the percentage that should be visible before a request is sent. (defaulted to `0.01`)\n\n(See https://github.com/thebuilder/react-intersection-observer#api)\n\n### Load before swap\n\nA common optimisation to the loading strategy is to preload the image before swapping it for the placeholder.\nIn other words, once the image is in view, you can kick off a request to load the image, and only show it once fully loaded.\nThis avoids presenting a half-loaded image (i.e. one that is still scanning top-to-bottom), and makes the transition smoother.\n\nThis behaviour is provided with the `src` prop:\n\n```jsx\n// Note that the actual src is also provided separately,\n// so that the image can be requested before rendering\n\u003cLazyImage\n  src=\"/img/porto_buildings_large.jpg\"\n  alt=\"Buildings with tiled exteriors, lit by the sunset.\"\n  placeholder={\n    ({imageProps, ref}) =\u003e\n      \u003cdiv ref={ref} className={`LazyImage-Placeholder`}\"\u003e\n        \u003cimg src=\"/img/porto_buildings_lowres.jpg\" alt={imageProps.alt} /\u003e\n      \u003c/div\u003e\n  }\n  actual={\n    ({imageProps}) =\u003e\n      \u003cdiv className={`LazyImage-Actual`}\u003e\n        \u003cimg {...imageProps} /\u003e\n      \u003c/div\u003e\n  }\n/\u003e\n```\n\nThere is another case if you are using `srcset` for your images; `LazyImage` needs that information to preload the correct image. You can provide it with the `srcSet` prop.\n\n### Loading and Error states\n\nYou can choose what to display on Loading and Error using the render props `loading` and `error`:\n\n```jsx\n\u003cdiv className=\"bg-light-silver h5 w-100\"\u003e\n  \u003cLazyImage\n    src=\"/image/brokenimagenotherewhoops.jpg\"\n    alt=\"Buildings with tiled exteriors, lit by the sunset.\"\n    actual={({ imageProps }) =\u003e \u003cimg {...imageProps} /\u003e}\n    placeholder={({ ref }) =\u003e \u003cdiv ref={ref} /\u003e}\n    loading={() =\u003e (\n      \u003cdiv\u003e\n        \u003cp className=\"pa3 f5 lh-copy near-white\"\u003eLoading...\u003c/p\u003e\n      \u003c/div\u003e\n    )}\n    error={() =\u003e (\n      \u003cdiv className=\"bg-light-red h-100 w-100\"\u003e\n        \u003cp\u003eThere was an error fetching this image :(\u003c/p\u003e\n      \u003c/div\u003e\n    )}\n  /\u003e\n\u003c/div\u003e\n```\n\n### Eager loading / Server-Side Rendering (SSR)\n\n**What does SSR even mean in a lazy images context?**\n\nIf you recall the basic premise, then you will know that we \"hide\" the intended image and display a placeholder.\nFor the actual image request to kick off, Javascript has to have loaded, and detected that the image is in the viewport.\nIn cases where you are server-side rendering, there can be a non-neglible amount of time until Javascript is available (i.e. it has to download, parse, execute).\nFor those cases, it would be beneficial if we can mark images to render with the intended/final src by default, so that the browser can start requesting them as soon as it gets the HTML.\n\nThis behaviour is available by using a `loadEagerly` prop:\n\n```jsx\n\u003cLazyImage\n  loadEagerly\n  src=\"/img/porto_buildings_large.jpg\"\n  alt=\"Buildings with tiled exteriors, lit by the sunset.\"\n  placeholder={({ imageProps, ref }) =\u003e (\n    \u003cimg ref={ref} src=\"/img/porto_buildings_lowres.jpg\" alt={imageProps.alt} /\u003e\n  )}\n  actual={({ imageProps }) =\u003e \u003cimg {...imageProps} /\u003e}\n/\u003e\n```\n\nWhile the usage is simple, the patterns in your app will not necessarily be so.\nThink about the cases where it is beneficial to do this, and apply it with intent.\nExamples might be eager-loading hero images, preloading the first few elements in a list and so on.\n[Some of these use cases are provided as examples](#examples).\n\n### Debounce / Delay\n\nIn cases where you have a long list of images that the user might scroll through, then loading intermediate images can waste bandwidth and processing time.\nThis is undesired.\nThe way to handle it is with a **minimum duration** that the image has to stay within the viewport, before making the request.\nThis is specified using the `debounceDurationMs` prop:\n\n```jsx\n\u003cLazyImage\n  src=\"/img/porto_buildings_large.jpg\"\n  alt=\"Buildings with tiled exteriors, lit by the sunset.\"\n  debounceDurationMs={1000}\n  placeholder={({ imageProps, ref }) =\u003e (\n    \u003cimg ref={ref} src=\"/img/porto_buildings_lowres.jpg\" alt={imageProps.alt} /\u003e\n  )}\n  actual={({ imageProps }) =\u003e \u003cimg {...imageProps} /\u003e}\n/\u003e\n```\n\n### Fallback without Javascript\n\nIf Javascript is disabled altogether by the user, then they will be stuck with the placeholder (and any images loaded eagerly).\nThis is probably undesirable.\n\nThere are a few strategies for fallbacks.\nMost of them are variations on a `\u003cnoscript\u003e` tag with the `actual` img and hiding the placeholder if JS is disabled.\nHere is what it looks like rendered:\n\n```jsx\n// In the \u003chead\u003e\n// Style applied only when JS is disabled\n// Hide the LazyImage (since the actual one will be displayed in its place)\n\u003cnoscript\u003e\n  \u003cstyle\u003e\n    .LazyImage {\n      display: none;\n    }\n  \u003c/style\u003e\n\u003c/noscript\u003e\n\n// Your component (as rendered)\n// Placeholder since JS has not run; will be hidden with the style above.\n\u003cimg class=\"LazyImage\" src=\"/img/porto_buildings_lowres.jpg\" alt=\"Buildings with tiled exteriors, lit by the sunset.\" /\u003e\n\n// Declare the actual image as you would, inside a noscript\n\u003cnoscript\u003e\n  \u003cimg src=\"/img/porto_buildings_large.jpg\" alt=\"Buildings with tiled exteriors, lit by the sunset.\" /\u003e\n\u003c/noscript\u003e\n```\n\nUntil v0.3.0, this library had a fallback API, in the form of a `fallback` render prop.\nThis has been disabled due to issues with `\u003cnoscript\u003e` in React causing the fallback to always load.\n\n(See https://github.com/facebook/react/issues/11423 for more details)\n\nCurrent solutions involve either using `dangerouslySetInnerHTML`, which is not safe for arbitrary library use, or `ReactDOMServer.renderToStaticMarkup`.\nI thought it would be irresponsible to hide the fact that `dangerouslySetInnerHTML` is used from the user, so that excludes the first option.\nI also think that using the server method, albeit safe, would be messy with some bundling configurations (which would keep the entirety of `react-dom/server`).\n\n**Silver lining:**\n\nThere is generally no case where `\u003cnoscript\u003e` will be rendered by client-side react.\nThis means that, if you are in charge of server-rendering and you trust your bundling setup, then you can have this fallback!\nLook at [`src/fallbackUtils.tsx`](./src/fallbackUtils.tsx) for a function that can work.\nYou would probably do something like this:\n\n```jsx\n\u003cLazyImage\n  src=\"actualImgSrc\"\n  alt=\"alt description here\"\n  placeholder={//the usual}\n  actual={//the usual}\n/\u003e\n\u003cFallback\u003e\n  \u003cimg src=\"/img/porto_buildings_large.jpg\" alt=\"Buildings with tiled exteriors, lit by the sunset.\" /\u003e\n\u003c/Fallback\u003e\n```\n\nDon't forget to also hide the `.LazyImage` as shown above.\n\nThis may or may not be good enough.\nPlease open an issue to discuss your needs if that is the case :)\n\n### Polyfill IntersectionObserver\n\nIntersectionObserver is generally well-supported, but it is still important to polyfill it!\n[You can consult the usage data for IntersectionObserver here.](https://caniuse.com/#search=intersectionobserver)\n\nThe polyfill itself is pretty small, [on the order of 6k min, 2k gzipped](https://bundlephobia.com/result?p=intersection-observer@0.5.0).\n\n[The polyfill is available through npm](http://npmjs.com/package/intersection-observer):\n\n```shell\nnpm install --save intersection-observer\n```\n\nAnd import it at your app's entry point:\n\n```js\nimport \"intersection-observer\";\n```\n\n[Polyfill.io is an alternative method of distributing the polyfill](https://polyfill.io) if you wish.\n\n#### About the polyfill\n\n_It is generally a good idea to know what you are adding to your codebase_\n\nThe polyfill behaviour is to [fall back to the older strategy](https://github.com/w3c/IntersectionObserver/tree/master/polyfill); \"debounced scroll listener and calculate bounding rectangle\", as mentioned above.\nIt will not be as performant as the native IntersectionObserver, but likely no worse than most implementations of the older strategy.\n\n## Examples\n\n### About understanding the library and loading patterns\n\nA variety of usage examples and recipes are provided in the form of Storybook.\n\n[You can browse the documentation online](https://fpapado.github.io/react-lazy-images) or look at `stories/`.\n\nRead the notes section either on Storybook or the story source if you are wondering about the specifics of each pattern demonstrated.\n\n### About abstracting over it and presentational patterns\n\n[The starter on Codesandbox](https://codesandbox.io/s/jnn9wjkj1w) has a good basis for two popular presentational patterns.\nIn particular, it shows intrinsic placeholders and fading in the actual image.\n\nYou might be thinking that this library has a lot of wiring exposed.\nThis is very much intended.\nIf this library were to provide presentational patterns out of the box, then it would lead to many issues and PRs about what ultimately is opinion.\nBeing inclined to fork a library just to add a prop is not a nice situation to be in, compared to writing one abstracted component for your specific use case.\nThe behaviour and loading patterns are configurable, because those are what this library is about.\nThe presentation can be derived from those plus, crucially, any specific needs your application has.\n\n## API Reference\n\n**`\u003cLazyImage /\u003e`** accepts the following props:\n\n| Name                   | Type                                                                      | Default                                   | Required | Description                                                                                                                                                                |\n| ---------------------- | ------------------------------------------------------------------------- | ----------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| **src**                | String                                                                    |                                           | true     | The source of the image to load                                                                                                                                            |\n| **alt**                | String                                                                    |                                           | false    | The alt text description of the image you are loading                                                                                                                      |\n| **srcSet**             | String                                                                    |                                           | false    | If your images use srcset, you can pass the `srcSet` prop to provide that information for preloading.                                                                      |\n| **sizes**              | String                                                                    |                                           | false    | If your images use srcset, the sizes attribute helps the browser decide which source to load.                                                                              |\n| **actual**             | Function (render callback) of type ({imageProps}) =\u003e React.ReactNode      |                                           | true     | Component to display once image has loaded                                                                                                                                 |\n| **placeholder**        | Function (render callback) of type ({imageProps, ref}) =\u003e React.ReactNode | undefined                                 | true     | Component to display while no request for the actual image has been made                                                                                                   |\n| **loading**            | Function (render callback) of type () =\u003e React.ReactNode                  | placeholder                               | false    | Component to display while the image is loading                                                                                                                            |\n| **error**              | Function (render callback) of type () =\u003e React.ReactNode                  | actual (broken image)                     | false    | Component to display if the image loading has failed (render prop)                                                                                                         |\n| **debounceDurationMs** | Number                                                                    | N/A                                       | false    | The minimum duration that the image has to be in the viewport before starting to load, in ms. This can help avoid loading images while the user scrolls quickly past them. |\n| **loadEagerly**        | Boolean                                                                   | false                                     | false    | Whether to skip checking for viewport and always show the 'actual' component                                                                                               |\n| **observerProps**      | {threshold: number, rootMargin: string}                                   | {threshold: 0.01, rootMargin: \"50px 0px\"} | false    | Subset of props for the IntersectionObserver                                                                                                                               |\n| **experimentalDecode** | Boolean                                                                   | false                                     | false    | Decode the image off-main-thread using the Image Decode API. Test before using!                                                                                            |\n\n**`\u003cLazyImageFull /\u003e`** accepts the following props:\n\n| Name                   | Type                                                                | Default                                   | Required | Description                                                                                           |\n| ---------------------- | ------------------------------------------------------------------- | ----------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------- |\n| **src**                | String                                                              |                                           | true     | The source of the image to load                                                                       |\n| **alt**                | String                                                              |                                           | false    | The alt text description of the image you are loading                                                 |\n| **srcSet**             | String                                                              |                                           | false    | If your images use srcset, you can pass the `srcSet` prop to provide that information for preloading. |\n| **sizes**              | String                                                              |                                           | false    | If your images use srcset, the sizes attribute helps the browser decide which source to load.         |\n| **debounceDurationMs** | Number                                                              | N/A                                       | false    | The minimum duration that the image has to be in the viewport before starting to load, in ms.         |\n| **loadEagerly**        | Boolean                                                             | false                                     | false    | Whether to skip checking for viewport and always show the 'actual' component                          |\n| **observerProps**      | {threshold: number, rootMargin: string}                             | {threshold: 0.01, rootMargin: \"50px 0px\"} | false    | Subset of props for the IntersectionObserver                                                          |\n| **children**           | Function of type ({imageProps, imageState, ref}) =\u003e React.ReactNode |                                           | true     | Function to call that renders based on the props and state provided to it by LazyImageFull            |\n| **experimentalDecode** | Boolean                                                             | false                                     | false    | Decode the image off-main-thread using the Image Decode API. Test before using!                       |\n\n[You can consult Typescript types in the code](./src/LazyImage.tsx) for more context.\n\n## Feedback\n\nI have some specific questions that I would like input on. If you want to go exploring, or have used the library and had gripes with it, then see [`FEEDBACK.md`](./FEEDBACK.md) and let's have a discussion!\n\n## Roadmap\n\nSee [`ROADMAP.md`](./ROADMAP.md) for information and ideas about where the project is headed.\n\n## Contributing\n\nI would love to have contributions on this! Are there more patterns that we can expose and simplify? Is something not clear? See `CONTRIBUTING.md` for details.\n\n## Thanks and Inspiration\n\nHere are some resources whose ideas resonate with me and have informed this library.\n\n- Jeremy Wagner's writing on [Lazy Loading Images and Video](https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video/) is a good reference for the problem and solutions space.\n\n- The library backing this one, [react-intersection-observer](https://github.com/thebuilder/react-intersection-observer).\n  Further thanks for demonstrating Storybook as documentation for lazy-loading.\n\n- [José M. Pérez has a good resource on lazy loading](https://jmperezperez.com/high-performance-lazy-loading/)\n\n- [Paul Lewis' implementation of lazy image loading](https://github.com/GoogleChromeLabs/sample-media-pwa/blob/master/src/client/scripts/helpers/lazy-load-images.js) has the concept of pre-loading images before swapping.\n\n- [Dave Rupert has a good guide on intrinsic image placeholders](https://daverupert.com/2015/12/intrinsic-placeholders-with-picture/)\n\n## License\n\nMIT License © Fotis Papadogeorgopoulos\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffpapado%2Freact-lazy-images","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffpapado%2Freact-lazy-images","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffpapado%2Freact-lazy-images/lists"}