{"id":28183,"date":"2022-03-24T20:53:51","date_gmt":"2022-03-24T20:53:51","guid":{"rendered":"http:\/\/infinite-scroll-images-in-nuxt.js-using-intersection-observer"},"modified":"2025-03-08T13:44:07","modified_gmt":"2025-03-08T21:44:07","slug":"infinite-scroll-images-in-nuxt-js-using-intersection-observer","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/","title":{"rendered":"Infinite scroll images with Intersection Observer"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>Building web applications involves displaying text, videos, and images to users. Sometimes, the sheer size of these assets could cause application lag; therefore, the need to display these assets in bits to users.<\/p>\n<p>Developers have devised several means of compressing images, and notable among these are applying pagination to make users\u2019 experience better. The use of an infinite scroll has proven to provide a better user experience.\nBuilding an infinite scroll into projects has gotten even easier with the introduction of the Intersection Observer API in browsers.<\/p>\n<p>This tutorial will walk you through implementing infinite scroll in an image gallery using the intersection observer web API.<\/p>\n<h2>Sandbox<\/h2>\n<p>The completed project can be found on <a href=\"https:\/\/codesandbox.io\/s\/infinite-scroll-using-intersection-observer-1j58m2\">CodeSandbox<\/a>. Fork it and run the code.<\/p>\n<\/div>\n  \n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/infinite-scroll-using-intersection-observer-1j58m2?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"Code Sandbox\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n  <div class=\"wp-block-cloudinary-markdown \"><h2>Github<\/h2>\n<p>Check out the complete source code in this <a href=\"https:\/\/github.com\/MoeRayo\/nuxt-infinte-scroll\">Github repository<\/a>.<\/p>\n<h2>What really is Infinite Scroll?<\/h2>\n<p>Infinite scroll is an interactive feature that automatically loads more content as the user scrolls through the page &#8211; meaning it creates a seemingly endless page.<\/p>\n<p>The interactivity has successfully eliminated the friction of pagination and led to increasing engagement &#8211; little wonder you\u2019d see it on almost all social media platforms and E-commerce websites.<\/p>\n<blockquote>\n<p>\u201cJust a few more shoes to check\u2026.\u201d But you never get to the end of the seemingly endless list of shoes before you doze right off!<\/p>\n<\/blockquote>\n<p>This tutorial will leverage the Intersection Observer API to achieve infinite scroll.<\/p>\n<h2>Intersection Observer API<\/h2>\n<p>The Intersection Observer API is a browser API that allows you to track a DOM element\u2019s location and visibility relative to a specified defined root element before calling a callback function if certain circumstances are satisfied.<\/p>\n<h3>What is the root element?<\/h3>\n<p>While monitoring the visibility of the target DOM element, the root element is the ancestor of the target element that acts as the viewport for checking the element\u2019s visibility.<\/p>\n<p>This <strong>root element<\/strong> will automatically traverse up the DOM tree to the browser\u2019s viewport if no target element is specified.<\/p>\n<p>There are several use cases for the Intersection Observer API, but the focus will be on implementing the infinite scroll.<\/p>\n<h2>Prerequisites<\/h2>\n<p>This tutorial assumes the reader has the following:<\/p>\n<ul>\n<li>Node.js installed on their computer<\/li>\n<li>Basic knowledge of JavaScript<\/li>\n<li>Familiarity with Nuxt.js<\/li>\n<li>\n<a href=\"https:\/\/tachyons.io\/\">Tachyons<\/a> CSS Toolkit<\/li>\n<li>Unsplash account<\/li>\n<\/ul>\n<h2>Dependencies Installation<\/h2>\n<h3>Creating a Nuxt.js Project<\/h3>\n<p>Open a terminal on your computer and run the following command.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npm init nuxt-app intersection-observer\ncd intersection-observer\nnpm run dev\n<\/code><\/span><\/pre>\n<p>Running <code>npm run dev<\/code>  starts the project on the development server at <code>localhost:3000<\/code> in your browser.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/moerayo\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1645637041\/let-us-begin_q0xzjp.gif\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"640\" height=\"354\"\/><\/p>\n<h3>Creating the Skeleton UI with static images<\/h3>\n<p>Before wading through an endless list of images, you\u2019ll build a skeleton interface to lay the foundation of your gallery.<\/p>\n<h3>Creating the gallery component<\/h3>\n<p>The grid of images across each row shows a photo gallery.\nNavigate to the <code>components<\/code> folder, create a <code>Gallery.vue<\/code> file and add the code block below.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"pv4 ph3 bg-washed-yellow h-100 mv3 mh2 br2\"<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"flex flex-wrap justify-between-l justify-center\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"db center mw5 tc black link dim\"<\/span> <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Frank Ocean's Blonde on Apple Music\"<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"https:\/\/geo.itunes.apple.com\/us\/album\/blonde\/id1146195596?at=1l3vqFJ&amp;mt=1&amp;app=music\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"db ba b--black-10\"<\/span> <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">\"Frank Ocean Blonde Album Cover\"<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"https:\/\/s3-us-west-1.amazonaws.com\/tachyonsio\/img\/Blonde-Frank_Ocean.jpeg\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dl<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"mt2 f6 lh-copy\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dt<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"clip\"<\/span>&gt;<\/span>Title<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dt<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dd<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"ml0\"<\/span>&gt;<\/span>Blonde<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dd<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dt<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"clip\"<\/span>&gt;<\/span>Artist<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dt<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dd<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"ml0 gray\"<\/span>&gt;<\/span>Frank Ocean<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dd<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dl<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Proceed to the <code>index.vue<\/code> file in the pages folder and import the <code>Gallery<\/code> component below the <code>GalleryHeader<\/code> component.\nAt this point, your <code>pages\/index.vue<\/code> should look like this:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">GalleryHeader<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Gallery<\/span> \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Your webpage should then look like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/mediadevs\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1647300463\/e-622f762c6cb5ad0068bc82c6\/uoj0j1macmt4trro4te5.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"886\" height=\"550\"\/><\/p>\n<h2>Adding Dynamic Images<\/h2>\n<p>After setting up the basic UI skeleton for the page, the next thing to be done is to add dynamic images that populate automatically from an API.\nThis article will be using the <a href=\"https:\/\/unsplash.com\/documentation\"><em>unsplash API<\/em><\/a><em>.<\/em> This tutorial focuses more on using the Intersection Observer API for infinite scroll. <a href=\"https:\/\/unsplash.com\/documentation\">Here<\/a> is a comprehensive guide written by the Unsplash team to guide you on setting up an Unsplash account up.<\/p>\n<p>At the end of this setup, your <code>components\/gallery.vue<\/code> should look like the below:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n  <span class=\"hljs-comment\">&lt;!--  repeated code removed --&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">v-for<\/span>=<span class=\"hljs-string\">\"image in imageList\"<\/span> <span class=\"hljs-attr\">:key<\/span>=<span class=\"hljs-string\">\"image.id\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"w-100 w-40-m w-30-l db center tc black link dim ma2\"<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"\"<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"db center ba b--black-10 ma2\"<\/span> <span class=\"hljs-attr\">:src<\/span>=<span class=\"hljs-string\">\"image.urls.small\"<\/span> <span class=\"hljs-attr\">:alt<\/span>=<span class=\"hljs-string\">\"image.alt_description\"<\/span> &gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dl<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"mt2 f6 lh-copy\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dt<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"clip\"<\/span>&gt;<\/span>Artist<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dt<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dd<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"ml0 gray\"<\/span>&gt;<\/span>{{image.user.name}}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dd<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dl<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span>&gt;<\/span><span class=\"javascript\">\n  <span class=\"hljs-keyword\">import<\/span> axios <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"axios\"<\/span>\n  <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> {\n    <span class=\"hljs-attr\">data<\/span>: <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> ({\n      <span class=\"hljs-attr\">imageList<\/span>: &#91;],\n      <span class=\"hljs-attr\">page<\/span>: <span class=\"hljs-number\">1<\/span>\n    }),\n    mounted(){\n      <span class=\"hljs-keyword\">this<\/span>.imageIntersected()\n    },\n    <span class=\"hljs-attr\">methods<\/span>: {\n      imageIntersected() {\n          axios\n            .get(\n              <span class=\"hljs-string\">`https:\/\/api.unsplash.com\/photos?page=<span class=\"hljs-subst\">${<span class=\"hljs-keyword\">this<\/span>.page}<\/span>&amp;per_page=21&amp;w=1280&amp;h=1280`<\/span>,\n              {\n                <span class=\"hljs-attr\">headers<\/span>: {\n                  <span class=\"hljs-attr\">Authorization<\/span>:\n                    <span class=\"hljs-string\">\"Client-ID {add your client-ID here}\"<\/span>,\n                  <span class=\"hljs-string\">\"Accept-Version\"<\/span>: <span class=\"hljs-string\">\"v1\"<\/span>\n                }\n              }\n            )\n          .then(<span class=\"hljs-function\"><span class=\"hljs-params\">response<\/span> =&gt;<\/span> {\n            <span class=\"hljs-keyword\">this<\/span>.page++;\n            <span class=\"hljs-keyword\">const<\/span> lists = response.data;\n            <span class=\"hljs-keyword\">this<\/span>.imageList = &#91;...this.imageList, ...lists];\n          })\n          .catch(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n            <span class=\"hljs-keyword\">this<\/span>.imageList = &#91;];\n        });\n      }\n    }\n  }\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The <code>imageIntersected<\/code> method gets dynamic images from the unsplash API in the code above. The <code>imageList<\/code> array displayed in the <code>v-for<\/code> gets populated with the data obtained when this method is mounted.<\/p>\n<p>Instead of Unsplash, you could use data of images stored locally or retrieved from an API.<\/p>\n<p>Your UI, in return, should look like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/mediadevs\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1647300629\/e-622f762c6cb5ad0068bc82c6\/zol2o45lyva4bmn2wiy3.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"948\" height=\"968\"\/><\/p>\n<p>Using the Intersection Observer API in your code involves several things &#8211; but foremost is using the object constructor function to create a new instance of the <code>Intersection Observer<\/code> like so:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">new<\/span> IntersectionObserver()\n    \n<span class=\"hljs-keyword\">const<\/span> observer = <span class=\"hljs-keyword\">new<\/span> IntersectionObserver(callbackFunction, options);\n<span class=\"hljs-keyword\">const<\/span> targetElement = <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">\".observer\"<\/span>);\n    \nobserver.observe(targetElement);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The <code>IntersectionObserver<\/code> receives two arguments &#8211; the first is the <em>callback function<\/em> and the second is the <em>options.<\/em><\/p>\n<ul>\n<li>\n<strong>Callback function:<\/strong>  The intersection of targeted elements with viewport execute the call back function.<\/li>\n<li>\n<strong>Options:<\/strong>  The options argument is optional, but its added function controls how the observer function executes.<\/li>\n<\/ul>\n<p><em>The<\/em> <em><strong>options<\/strong><\/em> <em>argument is an object and can have fields like:<\/em> <code>root<\/code>, <code>threshold<\/code> and <code>rootMargin<\/code>.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> options = {\n  <span class=\"hljs-attr\">root<\/span>: <span class=\"hljs-literal\">null<\/span>,\n  <span class=\"hljs-attr\">rootMargin<\/span>: <span class=\"hljs-string\">\"50px\"<\/span>,\n  <span class=\"hljs-attr\">threshold<\/span>: <span class=\"hljs-number\">1.0<\/span>\n};\nobserver.observe(targetElement, options);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<h2>Creating an observer component<\/h2>\n<p>With the basics of using the Intersection Observer API in your code being covered, get started with integrating it in your photo gallery project.\nCreate a <code>components\/Observer.vue<\/code> file and add the code below:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"observer\"<\/span>\/&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span>&gt;<\/span><span class=\"javascript\">\n  <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> {\n    <span class=\"hljs-attr\">props<\/span>: {\n      <span class=\"hljs-attr\">options<\/span>: {\n        <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-built_in\">Object<\/span>\n      }\n    },\n    <span class=\"hljs-attr\">data<\/span>: <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> ({\n      <span class=\"hljs-attr\">observer<\/span>: <span class=\"hljs-literal\">null<\/span>,\n    }),\n    mounted() {\n      <span class=\"hljs-keyword\">const<\/span> observerOptions = <span class=\"hljs-keyword\">this<\/span>.options || {};\n      <span class=\"hljs-keyword\">this<\/span>.observer = <span class=\"hljs-keyword\">new<\/span> IntersectionObserver(<span class=\"hljs-function\">(<span class=\"hljs-params\">&#91;entry]<\/span>) =&gt;<\/span> {\n      <span class=\"hljs-keyword\">if<\/span> (entry &amp;&amp; entry.isIntersecting) {\n        <span class=\"hljs-keyword\">this<\/span>.$emit(<span class=\"hljs-string\">\"intersect\"<\/span>);\n        }\n      }, observerOptions);\n        <span class=\"hljs-keyword\">this<\/span>.observer.observe(<span class=\"hljs-keyword\">this<\/span>.$el);\n      },\n      destroyed() {\n        <span class=\"hljs-keyword\">this<\/span>.observer.disconnect();\n    },\n  };\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<h3>Linking the Observer Component to the Gallery Component<\/h3>\n<p>Register the <code>Observer.vue<\/code> component in the <code>Gallery.vue<\/code> component to get the expected result.\nAt this point, <code>Gallery.vue<\/code> should look like this:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"pv4 ph3 bg-washed-yellow h-100 mv3 mh2 br2\"<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"flex flex-wrap justify-between-l justify-center\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span>\n        <span class=\"hljs-attr\">v-for<\/span>=<span class=\"hljs-string\">\"image in imageList\"<\/span>\n        <span class=\"hljs-attr\">:key<\/span>=<span class=\"hljs-string\">\"image.id\"<\/span>\n        <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"w-100 w-40-m w-30-l db center tc black link dim ma2\"<\/span>\n        <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"#\"<\/span>\n      &gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span>\n          <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"db center ba b--black-10 ma2\"<\/span>\n          <span class=\"hljs-attr\">:src<\/span>=<span class=\"hljs-string\">\"image.urls.small\"<\/span>\n          <span class=\"hljs-attr\">:alt<\/span>=<span class=\"hljs-string\">\"image.alt_description\"<\/span>\n        \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dl<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"mt2 f6 lh-copy\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dt<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"clip\"<\/span>&gt;<\/span>Artist<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dt<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dd<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"ml0 gray\"<\/span>&gt;<\/span>{{ image.user.name }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dd<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dl<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Observer<\/span> @<span class=\"hljs-attr\">intersect<\/span>=<span class=\"hljs-string\">\"imageIntersected\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span>&gt;<\/span><span class=\"javascript\">\n  <span class=\"hljs-keyword\">import<\/span> axios <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"axios\"<\/span>;\n  <span class=\"hljs-keyword\">import<\/span> Observer <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@\/components\/Observer\"<\/span>;\n  <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> {\n    <span class=\"hljs-attr\">components<\/span>: {\n      Observer,\n    },\n    <span class=\"hljs-attr\">data<\/span>: <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> ({\n      <span class=\"hljs-attr\">imageList<\/span>: &#91;],\n      <span class=\"hljs-attr\">page<\/span>: <span class=\"hljs-number\">1<\/span>,\n    }),\n    <span class=\"hljs-attr\">methods<\/span>: {\n      imageIntersected() {\n        axios\n          .get(\n            <span class=\"hljs-string\">`https:\/\/api.unsplash.com\/photos?page=<span class=\"hljs-subst\">${<span class=\"hljs-keyword\">this<\/span>.page}<\/span>&amp;per_page=10&amp;w=1280&amp;h=1280`<\/span>,\n          {\n            <span class=\"hljs-attr\">headers<\/span>: {\n              <span class=\"hljs-attr\">Authorization<\/span>: <span class=\"hljs-string\">`Client-ID {add your unsplash Client Id here}`<\/span>,\n              <span class=\"hljs-string\">\"Accept-Version\"<\/span>: <span class=\"hljs-string\">\"v1\"<\/span>,\n            },\n          }\n        )\n         .then(<span class=\"hljs-function\">(<span class=\"hljs-params\">response<\/span>) =&gt;<\/span> {\n           <span class=\"hljs-keyword\">this<\/span>.page++;\n           <span class=\"hljs-keyword\">const<\/span> lists = response.data;\n           <span class=\"hljs-keyword\">this<\/span>.imageList = &#91;...this.imageList, ...lists];\n         })\n        .catch(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n          <span class=\"hljs-keyword\">this<\/span>.imageList = &#91;];\n        });\n      },\n    },\n  };\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>At this point, more images should automatically load as you navigate through the application in your browser.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/mediadevs\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1647300057\/e-622f762c6cb5ad0068bc82c6\/mxfstigop1bwcdewh4xe.gif\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"368\" height=\"384\"\/><\/p>\n<h2>Conclusion<\/h2>\n<p>This post has gone through building a photo gallery that has infinite scroll implemented using the Intersection Observer and Unsplash APIs.<\/p>\n<p>The resources below will be helpful for further studies:<\/p>\n<ul>\n<li>\n<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Intersection_Observer_API\">MDN Docs on the Intersection Observer API<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/www.w3.org\/TR\/intersection-observer\/\">W3C Working Draft on the Intersection Observer API<\/a>\n<\/li>\n<\/ul>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28184,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,370,372,371],"class_list":["post-28183","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-image","tag-nuxtjs","tag-under-review"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Infinite scroll images with Intersection Observer<\/title>\n<meta name=\"description\" content=\"Learn how to create an infinite scroll image gallery using the intersection observer web API.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Infinite scroll images with Intersection Observer\" \/>\n<meta property=\"og:description\" content=\"Learn how to create an infinite scroll image gallery using the intersection observer web API.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-03-24T20:53:51+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-03-08T21:44:07+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1681925189\/Web_Assets\/blog\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c-png?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"886\" \/>\n\t<meta property=\"og:image:height\" content=\"550\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Infinite scroll images with Intersection Observer\",\"datePublished\":\"2022-03-24T20:53:51+00:00\",\"dateModified\":\"2025-03-08T21:44:07+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/\"},\"wordCount\":6,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925189\/Web_Assets\/blog\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c.png?_i=AA\",\"keywords\":[\"Guest Post\",\"Image\",\"NuxtJS\",\"Under Review\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/\",\"name\":\"Infinite scroll images with Intersection Observer\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925189\/Web_Assets\/blog\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c.png?_i=AA\",\"datePublished\":\"2022-03-24T20:53:51+00:00\",\"dateModified\":\"2025-03-08T21:44:07+00:00\",\"description\":\"Learn how to create an infinite scroll image gallery using the intersection observer web API.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925189\/Web_Assets\/blog\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925189\/Web_Assets\/blog\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c.png?_i=AA\",\"width\":886,\"height\":550},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Infinite scroll images with Intersection Observer\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Infinite scroll images with Intersection Observer","description":"Learn how to create an infinite scroll image gallery using the intersection observer web API.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/","og_locale":"en_US","og_type":"article","og_title":"Infinite scroll images with Intersection Observer","og_description":"Learn how to create an infinite scroll image gallery using the intersection observer web API.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-03-24T20:53:51+00:00","article_modified_time":"2025-03-08T21:44:07+00:00","og_image":[{"width":886,"height":550,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1681925189\/Web_Assets\/blog\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c-png?_i=AA","type":"image\/png"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/"},"author":{"name":"","@id":""},"headline":"Infinite scroll images with Intersection Observer","datePublished":"2022-03-24T20:53:51+00:00","dateModified":"2025-03-08T21:44:07+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/"},"wordCount":6,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925189\/Web_Assets\/blog\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c.png?_i=AA","keywords":["Guest Post","Image","NuxtJS","Under Review"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/","name":"Infinite scroll images with Intersection Observer","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925189\/Web_Assets\/blog\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c.png?_i=AA","datePublished":"2022-03-24T20:53:51+00:00","dateModified":"2025-03-08T21:44:07+00:00","description":"Learn how to create an infinite scroll image gallery using the intersection observer web API.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925189\/Web_Assets\/blog\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925189\/Web_Assets\/blog\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c.png?_i=AA","width":886,"height":550},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/infinite-scroll-images-in-nuxt-js-using-intersection-observer\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Infinite scroll images with Intersection Observer"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925189\/Web_Assets\/blog\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c\/f64c74619a852d2c9d324a1e5d6610ba30906aa1-886x550-1_281843b11c.png?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28183","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=28183"}],"version-history":[{"count":1,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28183\/revisions"}],"predecessor-version":[{"id":37143,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28183\/revisions\/37143"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28184"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28183"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28183"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28183"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}