{"id":13469621,"url":"https://github.com/wellyshen/react-cool-img","last_synced_at":"2025-05-15T16:04:34.551Z","repository":{"id":37686702,"uuid":"220604997","full_name":"wellyshen/react-cool-img","owner":"wellyshen","description":"😎 🏞 A React \u003cImg /\u003e component let you handle image UX and performance as a Pro!","archived":false,"fork":false,"pushed_at":"2023-08-12T16:40:36.000Z","size":12584,"stargazers_count":776,"open_issues_count":23,"forks_count":28,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-05-06T08:45:14.332Z","etag":null,"topics":["auto-retry","component","img","intersection-observer","lazy-loading","performance-optimization","placeholder","react","seo","ssr","typescript","ui","ux"],"latest_commit_sha":null,"homepage":"https://react-cool-img.netlify.app","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/wellyshen.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null},"funding":{"github":null,"patreon":null,"open_collective":"react-cool-img","ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2019-11-09T07:06:00.000Z","updated_at":"2025-05-04T02:57:41.000Z","dependencies_parsed_at":"2023-09-23T14:36:45.641Z","dependency_job_id":null,"html_url":"https://github.com/wellyshen/react-cool-img","commit_stats":{"total_commits":1257,"total_committers":6,"mean_commits":209.5,"dds":"0.45505171042163883","last_synced_commit":"becacd84c2d263a5570cad16ec4105fee030094e"},"previous_names":[],"tags_count":67,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wellyshen%2Freact-cool-img","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wellyshen%2Freact-cool-img/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wellyshen%2Freact-cool-img/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wellyshen%2Freact-cool-img/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wellyshen","download_url":"https://codeload.github.com/wellyshen/react-cool-img/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253446125,"owners_count":21909907,"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":["auto-retry","component","img","intersection-observer","lazy-loading","performance-optimization","placeholder","react","seo","ssr","typescript","ui","ux"],"created_at":"2024-07-31T15:01:47.222Z","updated_at":"2025-05-15T16:04:34.529Z","avatar_url":"https://github.com/wellyshen.png","language":"TypeScript","funding_links":["https://opencollective.com/react-cool-img"],"categories":["TypeScript"],"sub_categories":[],"readme":"# \u003cem\u003e\u003cb\u003eREACT COOL IMG\u003c/b\u003e\u003c/em\u003e\n\nThis is a lightweight React `\u003cImg /\u003e` component, which helps you handle image UX (user experience) and performance optimization as a professional guy 🤓\n\nIt empowers the standard [`img`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img) tag by many cool [features](#features) without breaking your original development experience. Ideally, it can be an `img` tag replacement for [React.js](https://reactjs.org).\n\n⚡️ Live demo: https://react-cool-img.netlify.app\n\n❤️ it? ⭐️ it on [GitHub](https://github.com/wellyshen/react-cool-img/stargazers) or [Tweet](https://twitter.com/intent/tweet?text=With%20@React-Cool-Img,%20my%20web%20app%20becomes%20more%20powerful.%20Thanks,%20@Welly%20Shen%20🤩) about it.\n\n[![build status](https://img.shields.io/github/workflow/status/wellyshen/react-cool-img/CI?style=flat-square)](https://github.com/wellyshen/react-cool-img/actions?query=workflow%3ACI)\n[![coverage status](https://img.shields.io/coveralls/github/wellyshen/react-cool-img?style=flat-square)](https://coveralls.io/github/wellyshen/react-cool-img?branch=master)\n[![npm version](https://img.shields.io/npm/v/react-cool-img?style=flat-square)](https://www.npmjs.com/package/react-cool-img)\n[![npm downloads](https://img.shields.io/npm/dm/react-cool-img?style=flat-square)](https://www.npmtrends.com/react-cool-img)\n[![npm downloads](https://img.shields.io/npm/dt/react-cool-img?style=flat-square)](https://www.npmtrends.com/react-cool-img)\n[![gzip size](https://badgen.net/bundlephobia/minzip/react-cool-img?label=gzip%20size\u0026style=flat-square)](https://bundlephobia.com/result?p=react-cool-img)\n[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange?style=flat-square)](#contributors-)\n[![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen?style=flat-square)](CONTRIBUTING.md)\n[![Twitter URL](https://img.shields.io/twitter/url?style=social\u0026url=https%3A%2F%2Fgithub.com%2Fwellyshen%2Freact-cool-img)](https://twitter.com/intent/tweet?text=With%20@react-cool-img,%20my%20web%20app%20becomes%20more%20powerful.%20Thanks,%20@Welly%20Shen%20🤩)\n\n## Features\n\n- 🖼 Placeholders for satisfying various image loading states (e.g. loading image \u003e actual image \u003e error image).\n- 🛋 [Smart lazy loading](#the-smart-way-to-load-images) with performant and efficient way, using [Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API).\n- 🤖 Built-in [auto-retry](#retry) mechanism. User won't miss out your important information.\n- 🚫 Aborts any current image downloads on component unmount potentially saving bandwidth and browser resources.\n- 🔍 [Supports server-side rendering / Javascript is disabled / SEO](#javascript-availability-and-seo).\n- 📜 Supports [TypeScript](https://www.typescriptlang.org) type definition.\n- 🦔 Tiny size ([~ 2kB gzipped](https://bundlephobia.com/result?p=react-cool-img)). No external dependencies, aside for the `react` and `react-dom`.\n- 🍰 Easy to use.\n\n\u003e ⚠️ [Most modern browsers support Intersection Observer natively](https://caniuse.com/#feat=intersectionobserver). You can also [add polyfill](#intersection-observer-polyfill) for full browser support.\n\n## Requirement\n\n`react-cool-img` is based on [React Hooks](https://reactjs.org/docs/hooks-intro.html). It requires `react v16.8+`.\n\n## Installation\n\nThis package is distributed via [npm](https://www.npmjs.com/package/react-cool-img).\n\n```sh\n$ yarn add react-cool-img\n# or\n$ npm install --save react-cool-img\n```\n\n## Quick Start\n\nThe [default props](#api) of the component has been fine-tuned for the purpose of loading optimization. Let's start it as the following example.\n\n```js\nimport Img from \"react-cool-img\";\n\n// Suggest to use low quality or vector images\nimport loadingImage from \"./images/loading.gif\";\nimport errorImage from \"./images/error.svg\";\n\nconst App = () =\u003e (\n  \u003cImg\n    placeholder={loadingImage}\n    src=\"https://the-image-url\"\n    error={errorImage}\n    alt=\"REACT COOL IMG\"\n  /\u003e\n);\n```\n\nDon't want an image placeholder? No worries, you can use [inline styles](https://reactjs.org/docs/dom-elements.html#style) or CSS for it. The component is fully compatible with the development experience of normal `img` tag.\n\n```js\nimport Img from \"react-cool-img\";\n\nconst App = () =\u003e (\n  \u003cImg\n    style={{ backgroundColor: \"grey\", width: \"480\", height: \"320\" }}\n    src=\"https://the-image-url\"\n    alt=\"REACT COOL IMG\"\n  /\u003e\n);\n```\n\n## API\n\nThe image component working similar with standard `img` tag and with the following props.\n\n| Prop              | Type    | Default                                                 | Description                                                                                                                                                                                                                     |\n| ----------------- | ------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `src`             | string  |                                                         | Image source. It's `required`. \u003cbr /\u003e[Support formats](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types)                                                                                                  |\n| `srcSet`          | string  |                                                         | Image sources for responsive images. For `src` prop only. \u003cbr /\u003e[Reference article](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images)                                             |\n| `sizes`           | string  |                                                         | Image sizes for responsive images. For `src` prop only. \u003cbr /\u003e[Reference article](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images)                                               |\n| `width`           | string  |                                                         | Width of the image in px.                                                                                                                                                                                                       |\n| `height`          | string  |                                                         | Height of the image in px.                                                                                                                                                                                                      |\n| `placeholder`     | string  |                                                         | Placeholder image source. \u003cbr /\u003e[Support formats](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types)                                                                                                       |\n| `error`           | string  |                                                         | Error image source. It'll replace Placeholder image. \u003cbr /\u003e[Support formats](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types)                                                                            |\n| `alt`             | string  |                                                         | An alternate text for an image section.                                                                                                                                                                                         |\n| `decode`          | boolean | `true`                                                  | Use [img.decode()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decode) to pre-decode the image before render it. Useful to prevent main thread from blocking by decoding of large image.                  |\n| `lazy`            | boolean | `true`                                                  | Turn on/off lazy loading. \u003cbr /\u003e[Using Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API)                                                                                       |\n| `cache`           | boolean | `true`                                                  | Instantly load images which have been cached when possible to abort the lazy loading behavior. \u003cbr /\u003e[Reference article](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching) |\n| `debounce`        | number  | `300`                                                   | How much to wait in milliseconds that the image has to be in viewport before starting to load. This can prevent images from being downloaded while the user scrolls quickly past them.                                          |\n| `observerOptions` | object  | `{ root: window, rootMargin: '50px', threshold: 0.01 }` | See the [observerOptions](#observeroptions) section.                                                                                                                                                                            |\n| `retry`           | object  | `{ count: 3, delay: 2, acc: '*' }`                      | See the [retry](#retry) section.                                                                                                                                                                                                |\n| `...`             |         |                                                         | Find more [props](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#Attributes) and [events](https://reactjs.org/docs/events.html#image-events).                                                                    |\n\n### observerOptions\n\nAll the properties are `optional`.\n\n- `root: Element | null` - the element that is used as the viewport for checking visibility of the target. Must be the ancestor of the target. Defaults to the browser viewport if not specified or if `null`.\n- `rootMargin: string` - margin around the root. Can have values similar to the CSS [margin](https://developer.mozilla.org/en-US/docs/Web/CSS/margin) property, e.g. `\"10px 20px 30px 40px\"` (top, right, bottom, left). The values can be percentages. This set of values serves to grow or shrink each side of the root element's bounding box before computing intersections.\n- `threshold: number` - a single number between 0 and 1, which indicate at what percentage of the target's visibility the observer's callback should be executed. A value of 0 means as soon as even one pixel is visible, the callback will be run. 1 means that the threshold isn't considered passed until every pixel is visible.\n\n### retry\n\nAll the properties are `optional`.\n\n- `count: number` - specifies the number of times you want to retry. Set it to 0 will disable auto-retry.\n- `delay: number` - specifies the delay between retries in seconds.\n- `acc: string | false` - specifies how the delay should be accumulated with each retry. It accepts the following values:\n  - `'*' (default)` - multiply delay after each subsequent retry by the given `delay` value, e.g. `delay: 2` means retry will run after 2 seconds, 4 seconds, 8 seconds, and so on.\n  - `'+'` - increment delay after each retry by the given `delay` value, e.g. `delay: 2` means retry will run after 2 seconds, 4 seconds, 6 seconds, and so on.\n  - `false` - keep the delay constant between retries, e.g. `delay: 2` means retry will run every 2 seconds.\n\n## The Smart Way to Load Images\n\nLazy image loading via the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) is good. But could it be greater to download an image only when user want to see it? Or bypass lazy loading for [cached images](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching)? The answer is yes and these features already be built into `react-cool-img` by the [`debounce` and `cache`](#api) props.\n\nBy the `debounce` prop, an image can wait to be downloaded while it's in the viewport for a set time. In cases where you have a long list of images that the user might scroll through inadvertently. At this time loading images can cause unnecessary waste of bandwidth and processing time.\n\n```js\nimport Img from \"react-cool-img\";\n\nimport defaultImg from \"./images/default.svg\";\n\nconst App = () =\u003e (\n  \u003cImg\n    placeholder={defaultImg}\n    src=\"https://the-image-url\"\n    debounce={1000} // Default is 300 (ms)\n    alt=\"REACT COOL IMG\"\n  /\u003e\n);\n```\n\nBy the `cache` prop, images you already have cached will abort lazy loading until user visit your app next time. Lazy loading is set up for any remaining images which were not cached. This is helpful for UX, because there's not much extra work to load cached images immediately and is an easy win for making the UI looks more intuitive.\n\n```js\nimport Img from \"react-cool-img\";\n\nimport defaultImg from \"./images/default.svg\";\n\nconst App = () =\u003e (\n  \u003cImg\n    placeholder={defaultImg}\n    src=\"https://the-image-url\"\n    cache // Default is true, just for demo\n    alt=\"REACT COOL IMG\"\n  /\u003e\n);\n```\n\n## JavaScript Availability and SEO\n\nThere're two challenges when doing lazy image loading with server-side rendering. One is Javascript availability the other is SEO. Fortunately, we can use [`\u003cnoscript\u003e`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/noscript) tag to solve these problems. It will render the actual image as fallback if Javascript is disabled thus user won't see the image which be stuck with the placeholder. Moreover, the `\u003cnoscript\u003e` tag ensure the image is indexed by search engine bots even if they cannot fully understand our JavaScript code. Take a look at how magic happens.\n\n```js\n// src/Img.tsx\n\nconst Img = () =\u003e {\n  // ...\n\n  return (\n    \u003c\u003e\n      \u003cimg\n        class=\"image\"\n        src=\"https://the-placeholder-image\"\n        alt=\"There's no magic\"\n      /\u003e\n      \u003cnoscript\u003e\n        \u003cimg\n          class=\"image\"\n          src=\"https://the-actual-image\"\n          alt=\"The magic begins in here...\"\n        /\u003e\n      \u003c/noscript\u003e\n    \u003c/\u003e\n  );\n};\n```\n\n## Intersection Observer Polyfill\n\n[Intersection Observer has good support amongst browsers](https://caniuse.com/#feat=intersectionobserver), but it's not universal. You'll need to polyfill browsers that don't support it. Polyfills is something you should do consciously at the application level. Therefore `react-cool-img` doesn't include it.\n\nYou can use W3C's [polyfill](https://www.npmjs.com/package/intersection-observer):\n\n```sh\n$ yarn add intersection-observer\n# or\n$ npm install --save intersection-observer\n```\n\nThen import it at your app's entry point:\n\n```js\nimport \"intersection-observer\";\n```\n\nOr use dynamic imports to only load the file when the polyfill is required:\n\n```js\n(async () =\u003e {\n  if (!(\"IntersectionObserver\" in window))\n    await import(\"intersection-observer\");\n})();\n```\n\n[Polyfill.io](https://polyfill.io/v3) is an alternative way to add the polyfill when needed.\n\n## Contributors ✨\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://wellyshen.com\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/21308003?v=4\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eWelly\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/wellyshen/react-cool-img/commits?author=wellyshen\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/wellyshen/react-cool-img/commits?author=wellyshen\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"#maintenance-wellyshen\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\u003c!-- markdownlint-enable --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwellyshen%2Freact-cool-img","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwellyshen%2Freact-cool-img","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwellyshen%2Freact-cool-img/lists"}