{"id":32956174,"url":"https://github.com/isaact/vue-infinity","last_synced_at":"2026-03-10T19:32:24.934Z","repository":{"id":293708119,"uuid":"970826226","full_name":"isaact/vue-infinity","owner":"isaact","description":"Vue Infinity is a lightweight library for creating resource efficient apps. Unload parts of your UI when not visible and build easy to layout virtual scrollers that can present unlimited content while keeping resource usage fixed.","archived":false,"fork":false,"pushed_at":"2025-12-19T10:03:03.000Z","size":38126,"stargazers_count":146,"open_issues_count":3,"forks_count":1,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-12-21T21:54:35.446Z","etag":null,"topics":["memory-ef","virtual-scroll","vue"],"latest_commit_sha":null,"homepage":"https://tewolde.co/vueInfinity/","language":"Vue","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/isaact.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-04-22T15:38:57.000Z","updated_at":"2025-12-18T20:14:27.000Z","dependencies_parsed_at":"2025-06-02T09:46:06.261Z","dependency_job_id":"d443f1fa-6ef4-4627-b374-4c79e0ded357","html_url":"https://github.com/isaact/vue-infinity","commit_stats":null,"previous_names":["isaact/vue-infinity"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/isaact/vue-infinity","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isaact%2Fvue-infinity","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isaact%2Fvue-infinity/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isaact%2Fvue-infinity/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isaact%2Fvue-infinity/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/isaact","download_url":"https://codeload.github.com/isaact/vue-infinity/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isaact%2Fvue-infinity/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30350076,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T15:55:29.454Z","status":"ssl_error","status_checked_at":"2026-03-10T15:54:58.440Z","response_time":106,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["memory-ef","virtual-scroll","vue"],"created_at":"2025-11-12T23:00:19.021Z","updated_at":"2026-03-10T19:32:24.925Z","avatar_url":"https://github.com/isaact.png","language":"Vue","funding_links":[],"categories":["Components \u0026 Libraries"],"sub_categories":["UI Components"],"readme":"\u003cdiv style=\"background-color: #444; width:100%;height:250px\"\u003e\n  \u003c!-- Cloud background (behind) --\u003e\n  \u003cimg\n    width=\"100%\"\n    height=\"250\"\n    src=\"assets/cloudsLogo.svg\"\n    alt=\"Decorative clouds\"\n    style=\"width:100%; height:250px\"\n  /\u003e\n\u003c/div\u003e\n\n# Vue-Infinity\n\n*Build lightning-fast Vue apps that only render what is on-screen*\n\nVue-Infinity brings a radical efficiency boost to your UI by applying the same principle that powers 3D engines: if it’s not in visible, it doesn’t get rendered. This lets your app handle hundreds or thousands of elements without bloating memory, janking or killing batteries.\n\nWhether you’re building infinite feeds, carousels, media galleries, or dashboards—Vue-Infinity keeps your app fast, smooth, and efficient.\n\n## Table of Contents\n\n- [Gallery Web Component](#-gallery-web-component)\n- [Carousel Component](#-carousel-component)\n- [InfiniteCarousel](#-infinitecarousel)\n- [Ghost Component](#-ghost-component)\n- [AutoObserver](#-autoobserver)\n- [Installation](#-installation)\n- [Live Demo](#-live-demo)\n- [Run Playground App](#-run-playground-app)\n- [Releases](#releases)\n- [License](#-license)\n\n## 🖼️ Gallery Web Component\n\nThe `gallery-ce` is a web component built on top of the Carousel component that provides an easy way to display a gallery of images with features like lazy loading, responsive layout, and dynamic sizing. It's designed to efficiently handle large collections of images while maintaining smooth performance.\n\n- **Easy to use**: Suitable when you have a big static list of images you want to browse\n- **Framework agnostic**: Can be used without Vue in any framework or vanilla JavaScript\n- **Flexible Layout**: Configurable grid layout with customizable columns and rows\n- **Lazy Loading**: Only renders visible images for optimal performance\n\n### Usage Examples\n\n#### Plain JavaScript\n\n```html\n\u003cgallery-ce id=\"gallery\" height=\"400px\" num-cols-to-show=\"3\"\u003e\u003c/gallery-ce\u003e\n\n\u003cscript type=\"module\"\u003e\n  import { registerElements } from 'vue-infinity';\n  registerElements();\n  \n  const gallery = document.getElementById('gallery');\n  gallery.updateImages([\n    'image1.jpg',\n    'image2.jpg',\n    'image3.jpg'\n  ]);\n\u003c/script\u003e\n```\n\n#### React\n\n```jsx\nimport { useEffect, useRef } from 'react';\nimport { registerElements } from 'vue-infinity';\n\nregisterElements();\n\nfunction Gallery() {\n  const galleryRef = useRef(null);\n  \n  useEffect(() =\u003e {\n    if (galleryRef.current) {\n      galleryRef.current.updateImages([\n        'image1.jpg',\n        'image2.jpg',\n        'image3.jpg'\n      ]);\n    }\n  }, []);\n  \n  return \u003cgallery-ce ref={galleryRef} height=\"400px\" num-cols-to-show=\"3\" /\u003e;\n}\n```\n\n#### Svelte\n\n```svelte\n\u003cscript\u003e\n  import { onMount } from 'svelte';\n  import { registerElements } from 'vue-infinity';\n  \n  registerElements();\n  \n  let gallery;\n  \n  onMount(() =\u003e {\n    gallery.updateImages([\n      'image1.jpg',\n      'image2.jpg',\n      'image3.jpg'\n    ]);\n  });\n\u003c/script\u003e\n\n\u003cgallery-ce bind:this={gallery} height=\"400px\" num-cols-to-show=\"3\" /\u003e\n```\n\n#### Vue\n\n```vue\n\u003ctemplate\u003e\n  \u003cgallery-ce ref=\"galleryRef\" height=\"400px\" :num-cols-to-show=\"3\" /\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { ref, onMounted } from 'vue';\nimport { registerElements } from 'vue-infinity';\n\nregisterElements();\n\nconst galleryRef = ref(null);\n\nonMounted(() =\u003e {\n  galleryRef.value.updateImages([\n    'image1.jpg',\n    'image2.jpg',\n    'image3.jpg'\n  ]);\n});\n\u003c/script\u003e\n```\n\n### Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `items` | String (JSON) | `'[]'` | Array of image URLs or objects with `url`, `title`, and `alt` properties |\n| `height` | String | `'400px'` | Height of the gallery container |\n| `width` | String | `'100%'` | Width of the gallery container |\n| `num-cols-to-show` | Number | `1` | Number of columns to show (can be fractional for partial items) |\n| `num-rows-to-show` | Number | `1` | Number of rows to show |\n| `gap` | String | `'1rem'` | Gap between items |\n| `vertical-scroll` | Boolean | `false` | Whether to scroll vertically instead of horizontally |\n\n### Methods\n\n| Method | Parameters | Description |\n|--------|------------|-------------|\n| `updateImages` | `newItems` (Array or JSON string) | Update the gallery with new images |\n| `scrollToItem` | `itemIndex` (Number) | Scroll to a specific item by index |\n\n**Note:** The `registerElements()` function must be called once before using any vue-infinity web components.\n\n## 🎠 Carousel Component\n\nThe Carousel component works like the Gallery but for any type of content. It provides a flexible way to display any kind of content in a carousel layout with lazy loading and responsive design.\n\n```vue\n\u003ctemplate\u003e\n  \u003cCarousel\n    :items=\"items\"\n    height=\"400px\"\n    :numColsToShow=\"3\"\n    gap=\"1rem\"\n  \u003e\n    \u003ctemplate #item=\"{ item, index }\"\u003e\n      \u003cdiv class=\"carousel-item\"\u003e\n        \u003ch3\u003e{{ item.title }}\u003c/h3\u003e\n        \u003cp\u003e{{ item.description }}\u003c/p\u003e\n      \u003c/div\u003e\n    \u003c/template\u003e\n  \u003c/Carousel\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { Carousel } from 'vue-infinity';\n\nconst items = [\n  { title: 'Item 1', description: 'Description 1' },\n  { title: 'Item 2', description: 'Description 2' },\n  { title: 'Item 3', description: 'Description 3' }\n];\n\u003c/script\u003e\n```\n\n## 🪂 InfiniteCarousel\n\nThe InfiniteCarousel works like the Carousel but with the ability to fetch more data as the user scrolls. It integrates with the `useInfiniteList` composable to handle data fetching and caching.\n\n### Creating an InfiniteList\n\n```javascript\nimport { useInfiniteList } from 'vue-infinity';\n\nconst infiniteList = useInfiniteList({\n  fetchItems: async (page, signal) =\u003e {\n    const response = await fetch(`/api/items?page=${page}`, { signal });\n    return response.json();\n  },\n  itemsPerPage: 50,\n  maxPagesToCache: 5\n});\n```\n\n### Using with InfiniteList\n\n```vue\n\u003ctemplate\u003e\n  \u003cInfiniteCarousel\n    :infinite-list=\"infiniteList\"\n    :height=\"'50vh'\"\n    :width=\"'100%'\"\n    :numColsToShow=\"3\"\n    :numRowsToShow=\"2\"\n  \u003e\n    \u003ctemplate #item=\"{ item, index }\"\u003e\n      \u003cimg :src=\"item.url\" :alt=\"item.title\" class=\"carousel-img\"/\u003e\n    \u003c/template\u003e\n  \u003c/InfiniteCarousel\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useInfiniteList } from 'vue-infinity';\n\nconst infiniteList = useInfiniteList({\n  fetchItems: (page) =\u003e fetchPage(page),\n  itemsPerPage: 20,\n  maxPagesToCache: 5\n});\n\u003c/script\u003e\n```\n\n## 👻 Ghost Component\n\nThe Ghost component is useful when you want to apply visibility based rendering to anything. It optimizes performance by conditionally rendering its slot content. When off-screen, the content is replaced by a dimensionally-identical placeholder.\n\n### Component Usage\n\n```vue\n\u003ctemplate\u003e\n  \u003cGhost @on-load=\"handleLoad\" @before-unload=\"handleBeforeUnload\" @on-unload=\"handleUnload\"\u003e\n    \u003cdiv style=\"height: 300px; background-color: lightblue;\"\u003e\n      This content will be replaced when not visible.\n    \u003c/div\u003e\n  \u003c/Ghost\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nconst handleLoad = () =\u003e {\n  console.log('Content is now visible and rendered.');\n};\n\nconst handleBeforeUnload = () =\u003e {\n  console.log('Content is about to be hidden.');\n};\n\nconst handleUnload = () =\u003e {\n  console.log('Content is hidden and replaced by a placeholder.');\n};\n\u003c/script\u003e\n```\n\n### Directive Usage\n\n```vue\n\u003ctemplate\u003e\n  \u003cdiv v-ghost=\"{\n    rootMargin: '100px',\n    onLoad: handleLoad,\n    beforeUnload: handleBeforeUnload,\n    onUnload: handleUnload\n  }\"\u003e\n    \u003c!-- Heavy content goes here --\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nconst handleLoad = () =\u003e {\n  console.log('Content is now visible and rendered.');\n};\n\nconst handleBeforeUnload = () =\u003e {\n  console.log('Content is about to be hidden.');\n};\n\nconst handleUnload = () =\u003e {\n  console.log('Content is hidden and replaced by a placeholder.');\n};\n\u003c/script\u003e\n```\n\n## 🔎 AutoObserver\n\nThe AutoObserver combines a MutationObserver and IntersectionObserver to allow you to track a container's child elements. It automatically handles new elements and cleaning up removed ones.\n\n- Get notified when elements get added\n- Get notified when elements become visible or when they are scrolled out of view\n\n```javascript\nconst containerRef = ref\u003cHTMLElement\u003e();\n\nconst { disconnect } = useAutoObserver(\n  containerRef,\n  (entries) =\u003e {\n    entries.forEach(entry =\u003e {\n      console.log('Element visibility changed:', entry.isIntersecting);\n    });\n  },\n  {\n    rootMargin: '200px',\n    threshold: 0.1,\n    filter: el =\u003e el.classList.contains('observe-me')\n  }\n);\n```\n\n## 📦 Installation\n\n```bash\nnpm install vue-infinity\n```\n\n## 🧪 Live Demo\n\nExplore the live demo here: [https://tewolde.co/vueInfinity/](https://tewolde.co/vueInfinity/)\n\n## 🧑‍💻 Run Playground App\n\nTo run the playground application locally:\n\n```bash\nnpm run playground\n```\n\n## Releases\n\n### v0.8.6 (2026-01-14)\n#### API Changes\n**InfiniteCarousel Component**:\n- Changed `startingPosition` prop to `startingIndex` for clarity\n- Added `scrollPosition` event emit to track scroll position as a fraction (0-1)\n- Added two-way binding support for `scrollPosition` via `v-model:scrollPosition`\n- Updated Playground app to reflect these changes\n\n### v0.8.5 (2025-12-10)\n#### Bug Fixes\n**InfiniteCarousel Component**:\n- Fixed issue where updating `startingPosition` did not scroll to the correct item\n\n\n### v0.8.4 (2025-11-26)\n\n#### Enhancements\n**InfiniteCarousel Component**:\n- Added `startingPosition` prop with two-way binding support (`v-model:startingPosition`)\n- Integrated `useSortedElements` composable for improved top-left item detection\n\n**Playground App**:\n- Updated to show `startingPosition` control for InfiniteCarousel\n\n\n### v0.8.0 (2025-08-11)\n\n#### New Components and Features\n**Gallery Web Component**:\n- Simple: Easy to use web component for displaying image galleries with lazy loading, responsive layout and memory efficiency.\n- Framework Agnostic: Use in any frontend framework or even plain JavaScript.\n- Flexible: Methods to update images and scroll to specific items\n- Playground App: Added a demo for the Gallery component in the playground app.\n- Documentation Updates: Added comprehensive examples for Vue, React, Svelte, and plain JavaScript\n**Carousel Component**:\n- Similar to the Gallery but for any type of content.\n- Supports lazy loading, easy layout and memory efficiency.\n- Supports custom item templates and dynamic content sizing.\n\n### v0.7.0 (2024-07-01)\n\n- **v-ghost Directive**: Introduced the new `v-ghost` directive to optimize performance by automatically unloading off-screen content.\n- **Dynamic Item Sizing**: The `InfiniteCarousel` now supports an `onGetItemAspectRatio` callback, enabling it to render items with variable heights.\n- **Documentation Updates**: Added instructions for the `v-ghost` directive and the dynamic sizing feature.\n\n## 📄 License\n\nApache 2.0 License - [https://opensource.org/licenses/Apache-2.0](https://opensource.org/licenses/Apache-2.0)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fisaact%2Fvue-infinity","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fisaact%2Fvue-infinity","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fisaact%2Fvue-infinity/lists"}