npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

paginateflow-sdk

v0.1.0

Published

EU Infinite Scrolling Compliance SDK - Drop-in React pagination for GDPR compliance

Readme

@vibecaas/paginate-flow

npm version License: MIT

EU Infinite Scrolling Compliance SDK - A drop-in React pagination library for GDPR/DSA compliance with virtual scrolling for high-performance rendering.

🌍 Why PaginateFlow?

The EU's Digital Services Act (DSA) bans manipulative infinite scrolling on social platforms. PaginateFlow provides a compliant alternative with:

  • GDPR/DSA Compliant - Explicit pagination replaces infinite scrolling
  • Virtual Scrolling - Renders only visible items (10,000+ items without lag)
  • Auto Load Detection - Triggers 500px before end of list
  • Analytics Hooks - Track page loads, scroll depth, and user engagement
  • Zero Runtime Dependencies - Only TanStack Virtual as peer dependency
  • Small Bundle - ~23KB unzipped (6.88KB gzipped)

📦 Installation

npm install @vibecaas/paginate-flow @tanstack/react-virtual

or

yarn add @vibecaas/paginate-flow @tanstack/react-virtual

or

pnpm add @vibecaas/paginate-flow @tanstack/react-virtual

🚀 Quick Start

import { VirtualizedList } from '@vibecaas/paginate-flow';

function App() {
  const [items, setItems] = useState([]);
  const [hasMore, setHasMore] = useState(true);

  const fetchNextPage = async () => {
    const newItems = await fetch('/api/items?page=' + currentPage);
    setItems(prev => [...prev, ...newItems]);
    setHasMore(newItems.length > 0);
  };

  return (
    <VirtualizedList
      items={items}
      renderItem={(item) => <Card key={item.id} {...item} />}
      onLoadMore={fetchNextPage}
      hasMore={hasMore}
      estimatedItemHeight={150}
      height="100vh"
    />
  );
}

📚 Components

VirtualizedList

The main component for efficient list rendering with pagination.

<VirtualizedList<T>
  items={T[]}
  renderItem={(item: T, index: number) => ReactNode}
  getItemKey?: (item: T, index: number) => string | number
  estimatedItemHeight?: number  // Default: 80px
  height?: number | string  // Default: "100vh"
  onLoadMore?: () => void | Promise<void>
  hasMore?: boolean
  loadMoreThreshold?: number  // Default: 500px
  analytics?: AnalyticsHandlers
  loadingComponent?: ReactNode
  showComplianceBadge?: boolean  // Default: true
  footer?: ReactNode
/>

LoadMoreButton

A standalone button component for manual load more triggers.

<LoadMoreButton
  hasMore={boolean}
  isLoading?: boolean
  onLoadMore={() => void | Promise<void>}
  loadingLabel?: string
  idleLabel?: string
  disabled?: boolean
  className?: string
/>

ComplianceBadge

GDPR compliance badge component.

<ComplianceBadge
  position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
  label?: string
  className?: string
  showTooltip?: boolean
  tooltipText?: string
/>

🪝 Hooks

usePagination

Manage pagination state.

const { state, nextPage, prevPage, goToPage, reset } = usePagination({
  itemsPerPage: 20,
  initialPage: 1,
  totalItems: 100,
  fetchPage: async (page: number) => { ... }
});

// State: { currentPage, totalPages, itemsPerPage, totalItems, isLoading, hasMore }

useScrollAnalytics

Track scroll events for analytics.

const { scrollDepth, handleScroll, resetTracking, trackPageLoad, trackItemRender } = useScrollAnalytics({
  analytics: {
    onPageLoad: (page) => Analytics.track('page_loaded', { page }),
    onScrollDepth: (depth) => Analytics.track('scroll_depth', { depth }),
    onItemRender: (item, index) => Analytics.track('item_rendered', { index })
  },
  throttleMs: 100
});

📊 Analytics Integration

PaginateFlow provides hooks for tracking user engagement:

<VirtualizedList
  items={items}
  renderItem={renderItem}
  onLoadMore={fetchNextPage}
  hasMore={hasMore}
  analytics={{
    onPageLoad: (page) => {
      // Fire when a new page loads
      console.log('Page loaded:', page);
      Analytics.track('page_loaded', { page });
    },
    onItemRender: (item, index) => {
      // Fire when an item is rendered
      console.log('Item rendered:', index);
      Analytics.track('item_rendered', { index });
    },
    onScrollDepth: (depth) => {
      // Fire when scroll depth changes
      console.log('Scroll depth:', depth);
      Analytics.track('scroll_depth', {
        page: depth.page,
        percentage: depth.percentage,
        visibleItems: depth.visibleItems,
        totalItems: depth.totalItems,
      });
    },
  }}
/>

🎨 Styling

PaginateFlow is styled with Tailwind CSS classes. The components expose className props for customization:

<LoadMoreButton className="w-full max-w-md mx-auto" />
<ComplianceBadge className="top-4 right-4" />

🔧 TypeScript

Full TypeScript support with exported types:

import type {
  VirtualizedListProps,
  AnalyticsHandlers,
  ScrollDepth,
  PaginationState,
  UsePaginationOptions
} from '@vibecaas/paginate-flow';

📝 Example Usage

See the demo app for a complete implementation or visit the live demo at:

demo.paginateflow.dev

Mock Data Example

const generatePosts = (startId: number, count: number) => {
  return Array.from({ length: count }, (_, i) => ({
    id: startId + i,
    title: `Post #${startId + i}`,
    content: '...',
  }));
};

<VirtualizedList
  items={posts}
  renderItem={(post) => <PostCard key={post.id} {...post} />}
  onLoadMore={() => {
    const newPosts = generatePosts(posts.length, 20);
    setPosts(prev => [...prev, ...newPosts]);
  }}
  hasMore={posts.length < 200}
  analytics={analytics}
/>

🧪 Performance

  • ✅ Renders 10,000+ items without lag
  • ✅ Only renders visible items (virtual scrolling)
  • ✅ Debounced scroll events (100ms default)
  • ✅ Optimized re-rendering with React.memo

🛡️ GDPR/DSA Compliance

PaginateFlow helps you comply with:

  • EU Digital Services Act (DSA) - Article 25 bans dark patterns like infinite scrolling
  • GDPR Article 25 (Data Protection by Design) - Explicit user control over content consumption

The compliance badge signals to users that your app respects EU regulations.

📦 Bundle Size

dist/index.js  22.84 kB │ gzip: 6.88 kB

Under 4 MB constraint (achieved ✅)

🔗 Dependencies

Peer Dependencies (must be installed separately):

  • react ^18.0.0 || ^19.0.0
  • react-dom ^18.0.0 || ^19.0.0

Runtime Dependencies:

  • @tanstack/virtual-core ^3.10.7
  • @tanstack/react-virtual ^3.10.7

📄 License

MIT © 2026 VibeCaaS

🤝 Contributing

Contributions welcome! Please read our contributing guidelines.

📮 Support


Built with ❤️ for EU compliance ⚖️️🇪🇺