Skip to content

feat: leaderboard displays all stats at once with no pagination β€” as the student count grows, rendering 200+ table rows simultaneously degrades browser performance and scroll UXΒ #295

Description

@divyanshim27

πŸš€ Problem Statement

The frontend/ leaderboard page fetches all users from leetcode-ranking-data and renders them in a single HTML table. Based on the project's growth trajectory (PVG COET has thousands of CS students), this will scale to 200-500 rows as more students register.

A single DOM with 500 <tr> elements (each with 6-8 cells including solved counts, badges, and ranking positions) causes:

  1. Initial render lag: 500 rows Γ— 8 cells = 4,000 DOM nodes rendered at once
  2. Scroll jank: The browser must layout and paint all 4,000 nodes even when only 15 are visible
  3. Poor mobile experience: On a phone, a 500-row table is nearly unusable

Proposed Fix

Add client-side virtual scrolling + pagination in the frontend/ JavaScript:

// frontend/js/leaderboard.js

const PAGE_SIZE = 25;
let currentPage = 1;
let allUsers = [];
let filteredUsers = [];

function renderPage(users, page) {
  const start = (page - 1) * PAGE_SIZE;
  const end = start + PAGE_SIZE;
  const pageUsers = users.slice(start, end);
  const tbody = document.querySelector('#leaderboard tbody');

  tbody.innerHTML = '';
  pageUsers.forEach((user, i) => {
    const rank = start + i + 1;
    tbody.insertAdjacentHTML('beforeend', buildRow(user, rank));
  });

  updatePaginationControls(users.length, page);
}

function updatePaginationControls(totalUsers, currentPage) {
  const totalPages = Math.ceil(totalUsers / PAGE_SIZE);
  const pagination = document.getElementById('pagination');
  pagination.innerHTML = `
    <button onclick="goToPage(${currentPage - 1})" ${currentPage === 1 ? 'disabled' : ''}>← Prev</button>
    <span>Page ${currentPage} of ${totalPages} (${totalUsers} students)</span>
    <button onclick="goToPage(${currentPage + 1})" ${currentPage === totalPages ? 'disabled' : ''}>Next β†’</button>
  `;
}

function goToPage(page) {
  currentPage = Math.max(1, Math.min(page, Math.ceil(filteredUsers.length / PAGE_SIZE)));
  renderPage(filteredUsers, currentPage);
  window.scrollTo({ top: 0, behavior: 'smooth' });
}

Also add a search/filter bar above the table to filter by student name or username in real-time (since the full dataset is already loaded client-side, filtering is instant):

document.getElementById('search').addEventListener('input', (e) => {
  const query = e.target.value.toLowerCase().trim();
  filteredUsers = query
    ? allUsers.filter(u => u.name.toLowerCase().includes(query) || u.username.toLowerCase().includes(query))
    : allUsers;
  currentPage = 1;
  renderPage(filteredUsers, currentPage);
});

Files to Modify

File Change
frontend/ (leaderboard JS) Add renderPage(), goToPage(), pagination controls, search filter
frontend/ (leaderboard HTML) Add <input id="search"> and <div id="pagination">
frontend/ (leaderboard CSS) Style pagination controls and search bar

Suggested labels: enhancement, frontend, performance, level: beginner

I would like to work on this. Could you please assign it to me?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions