joyco

Infinite List

Cards 64

About

A bias-based infinite scroll wrapper and hook that manages pagination and masks child items for progressive "load more" lists.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Infinite List to your project and fits it to your theme.

Code

How Infinite List is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

'use client'

import { MaskedList, useInfiniteList } from '@/components/ui/infinite-list'
import Image from 'next/image'
import { useEffect, useState, useTransition } from 'react'
import { Button } from '@/components/ui/button'
import { Card, CardFooter } from '@/components/ui/card'

type Pokemon = { name: string; url: string; image: string }

async function fetchPokemon(offset: number, limit: number): Promise<Pokemon[]> {
  const res = await fetch(
    `https://pokeapi.co/api/v2/pokemon?offset=${offset}&limit=${limit}`
  ).then((r) => r.json())
  return Promise.all(
    res.results.map(async (p: { url: string }) => {
      const data = await fetch(p.url).then((r) => r.json())
      return { name: data.name, url: p.url, image: data.sprites.front_default }
    })
  )
}

export default function InfiniteListDemo() {
  const pageSize = 12
  const [pokemon, setPokemon] = useState<Pokemon[]>([])
  const [isPending, startTransition] = useTransition()
  const list = useInfiniteList({ pageSize, initialItems: pokemon })

  useEffect(() => {
    fetchPokemon(0, pageSize * 2).then(setPokemon)
  }, [])

  const loadMore = () => {
    list.nextPage()
    startTransition(async () => {
      const newPokemon = await fetchPokemon(list.offset, pageSize)
      setPokemon((prev) => [...prev, ...newPokemon])
    })
  }

  return (
    <div className="relative h-[500px] w-full overflow-auto">
      <div className="bg-background/90 border-border sticky top-4 right-8 z-10 ml-auto w-fit rounded-lg border px-3 py-2 font-mono text-xs">
        DISPLAYED: {Math.min(list.displayLimit, pokemon.length)} | LOADED:{' '}
        {pokemon.length}
      </div>
      <div className="flex flex-col gap-6 p-6">
        <h2 className="text-2xl font-semibold">Pokemon Infinite List</h2>
        <div className="mb-6 grid grid-cols-2 gap-3 md:grid-cols-3">
          <MaskedList {...list}>
            {pokemon.map((p) => (
              <Card key={p.url} className="gap-0 overflow-hidden p-0">
                <div className="bg-muted aspect-square">
                  <Image
                    src={p.image}
                    alt={p.name}
                    width={500}
                    height={500}
                    className="h-full w-full object-cover [image-rendering:pixelated]"
                    unoptimized
                  />
                </div>
                <CardFooter className="p-4">
                  <h3 className="text-base font-semibold capitalize">
                    {p.name}
                  </h3>
                </CardFooter>
              </Card>
            ))}
          </MaskedList>
        </div>

        <Button
          onClick={loadMore}
          disabled={isPending}
          variant="outline"
          className="self-center shadow-none transition-none"
        >
          {isPending ? 'Loading...' : 'Load More'}
        </Button>
      </div>
    </div>
  )
}

Dependencies

More by joyco

View all
  • Image Sequence

    Image Sequence

    69
  • File Dropzone

    File Dropzone

    19
  • HLS Video Player

    HLS Video Player

    18
  • Action Hint

    Action Hint

    16
  • Chat

    Chat

    15
  • Spritesheet Sequencer

    Spritesheet Sequencer

    11
  • Snake Game

    Snake Game

    2
  • Typewriter

    Typewriter

    2

More in Cards

View all
  • Stats cards with links

    Stats cards with links

    39
  • Statistics Card 2

    Statistics Card 2

    261
  • Course Design Cards

    Course Design Cards

    1.1K
  • The Item one

    The Item one

    3
  • Card

    Card

    70
  • Card Studio

    Card Studio

    7
  • Statistics Card 7

    Statistics Card 7

    289
  • Card

    Card

    17