DEV Community

Ekta Prajapati
Ekta Prajapati

Posted on

How to create pagination in Svelte

What pagination is and why it’s important.

Pagination is a common UI feature that allows users to navigate through large sets of data efficiently. In this tutorial, we will create a reusable pagination component in Svelte. Whether you're new to Svelte or looking to sharpen your skills, this guide is for you!

Create a svelte app by run this command.

npx sv create myapp
cd myapp
npm install
npm run dev
Enter fullscreen mode Exit fullscreen mode

Create Pagination.svelte component

In the script tag create a state totalPage, currentPage, and paginationRange. paginationRange for how many pages you want to display for the pagination logic.

 // Declare total pages, current page, and the pagination range
 let totalPages = $state(10);
 let currentPage = $state(1);
 let paginationRange = $stage(); // Array for pagination buttons

Enter fullscreen mode Exit fullscreen mode

Now, we create a range using the getPaginationRange() function.
add this function to your script.

  // Define the function for the pagination range
  const getPaginationRange = (total: number, current: number) => {
    let range: Array<{ value: number | string; id: string }> = [];
    if (total <= 6) {
      for (let i = 1; i <= total; i++) {
        range.push({ value: i, id: `p_${i}` });
      }
    } else {
      if (current <= 2) {
        range = [
          { value: 1, id: "p_1" },
          { value: 2, id: "p_2" },
          { value: 3, id: "p_3" },
          { value: "...", id: "d_1" },
          { value: total - 2, id: `p_${total - 2}` },
          { value: total - 1, id: `p_${total - 1}` },
          { value: total, id: `p_${total}` },
        ];
      } else if (current === 3) {
        range = [
          { value: 1, id: "p_1" },
          { value: "...", id: "d_1" },
          { value: 2, id: "p_2" },
          { value: 3, id: "p_3" },
          { value: 4, id: "p_4" },
          { value: "...", id: "d_2" },
          { value: total, id: `p_${total}` },
        ];
      } else if (current >= 4 && current <= total - 3) {
        range = [
          { value: 1, id: "p_1" },
          { value: "...", id: "d_1" },
          { value: current - 1, id: `p_${current - 1}` },
          { value: current, id: `p_${current}` },
          { value: current + 1, id: `p_${current + 1}` },
          { value: "...", id: "d_2" },
          { value: total, id: `p_${total}` },
        ];
      } else {
        range = [
          { value: 1, id: "p_1" },
          { value: 2, id: "p_2" },
          { value: 3, id: "p_3" },
          { value: "...", id: "d_1" },
          { value: total - 2, id: `p_${total - 2}` },
          { value: total - 1, id: `p_${total - 1}` },
          { value: total, id: `p_${total}` },
        ];
      }
    }
    return range;
  };
Enter fullscreen mode Exit fullscreen mode
  $effect(() => {
    paginationRange = getPaginationRange(totalPages, currentPage);
  });

Enter fullscreen mode Exit fullscreen mode

In Svelte, $effect is a directive from the Svelte Store API that automatically reacts to changes in any reactive state and executes a specific piece of logic. It’s commonly used to create derived or dependent values based on other reactive states.

  • $effect reacts to changes in totalPages or currentPage.
  • When either of these states is updated, $effect recalculates the paginationRange using the getPaginationRange function.
  • This ensures the pagination buttons reflect the current state of the pagination.

Now implement HTML code to see how pagination looks.

<div class="pagination-container">
  <ul class="pagination">
    <!-- Previous Button -->
    <button
      aria-label="previous page"
      class="pagination-item prev-next"
      class:disabled={currentPage === 1}
      onclick={() => handlePageClick(currentPage - 1)}
    >
      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
        <path d="M15 18l-6-6 6-6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
      </svg>
    </button>

    <!-- Pagination Items -->
    {#each paginationRange as { value, id } (id)}
      <button
        class="pagination-item"
        class:active={value === currentPage}
        class:disabled={value === "..."}
        onclick={() => handlePageClick(value)}
      >
        {value}
      </button>
    {/each}

    <!-- Next Button -->
    <button
      aria-label="next page"
      class="pagination-item prev-next"
      class:disabled={currentPage === totalPages}
      onclick={() => handlePageClick(currentPage + 1)}
    >
      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
        <path d="M9 18l6-6-6-6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
      </svg>
    </button>
  </ul>
</div>

Enter fullscreen mode Exit fullscreen mode

Add the handlePageClick function in script.

// Page click handler
  const handlePageClick = (page: number | string) => {
    if (typeof page === "number" && page >= 1 && page <= totalPages) {
      currentPage = page;
    }
  };
Enter fullscreen mode Exit fullscreen mode
  • When a user clicks on a pagination button, this function determines whether the clicked value is a valid page number.

  • If valid, it updates the currentPage state.

  • Updating currentPage automatically triggers $effect to recalculate the paginationRange, ensuring the pagination display is in sync with the current page.

To make pagination more attractive add CSS style into your code.

<style>

.pagination-container {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    flex: 1;
    width: 100%;
    align-items: center;
    justify-content: center;
}

  .pagination {
    display: flex;
    list-style: none;
    gap: 8px;
    align-items: center;
    padding: 0;
  }

  .pagination-item {
    min-width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    border-radius: 12px;
    font-weight: 600;
    transition: all 0.3s ease;
    user-select: none;
    color: #626262;
  }

  .pagination-item:hover:not(.disabled) {
    background-color: #f0f2f5;
    color: #7367f0;
  }

  .pagination-item.active {
    background-color: #7367f0;
    color: white;
    box-shadow: 0 0 10px rgba(115, 103, 240, 0.3);
  }

  .pagination-item.disabled {
    color: #c2c2c2;
    pointer-events: none;
    cursor: not-allowed;
  }

  .prev-next {
    background-color: #f0f2f5;
    border-radius: 12px;
  }

  .prev-next:hover:not(.disabled) {
    background-color: #7367f0;
    color: white;
  }
</style>

Enter fullscreen mode Exit fullscreen mode

Image description

Conclusion

Congratulations! You've built a fully functional and reusable pagination component in Svelte. Try integrating it with an API to fetch data dynamically or use it in your projects. Happy coding!
checkout this example here svelte-pagination

Top comments (0)