Pagination
Page controls for navigating long lists of paged content.
Code
// Pagination.tsx
import React from 'react'
import { PaginationProvider } from './PaginationContext'
interface PaginationProps {
activePage: number
totalPages: number
maxButtons?: number
onPageChange: (page:number) => void
children: React.ReactNode
}
const Pagination = ({activePage, totalPages, maxButtons = 5, onPageChange, children}: PaginationProps) => {
return (
<nav role="navigation" aria-label="pagination" className="flex flex-row items-center justify-center w-full">
<PaginationProvider
activePage={activePage}
totalPages={totalPages}
maxButtons={maxButtons}
onPageChange={onPageChange}
>
{children}
</PaginationProvider>
</nav>
)
}
export default Pagination
// PaginationContent.tsx
import { usePagination } from "./PaginationContext"
import { Ellipsis } from "lucide-react"
const PaginationContent = () => {
const {pagesToRender, activePage, onPageChange} = usePagination()
return (
<ul className = "flex flex-row items-center gap-1">
{pagesToRender.map((item, index) => {
const isActive = item === activePage;
if (typeof item === 'string'){
return (
<li key = {`ellipsis-${index}`}><Ellipsis size={`16px`} className="text-gray-800"/></li>
)
}
return (
<li key = {item}>
<button
className = {`text-sm rounded-md h-7 w-7 text-gray-800 hover:bg-gray-100 ${
isActive ? " border rounded-md font-medium border-gray-300" : ""}`}
aria-current = {isActive ? "page" : undefined}
onClick = {() => onPageChange(item)}
>
{item}
</button>
</li>
)
})}
</ul>
)
}
export default PaginationContent
// PaginationPrevious.tsx
import React from 'react'
import { ChevronLeft } from 'lucide-react'
import { usePagination } from './PaginationContext'
const PaginationPrevious = () => {
const {activePage, onPageChange} = usePagination();
const isDisabled = activePage === 1;
return (
<button
disabled = {isDisabled}
className = {`text-sm font-medium rounded-md h-7 w-7 mr-2 flex justify-center items-center ${
isDisabled ? "text-gray-300 cursor-not-allowed" : "text-gray-500 hover:bg-gray-100"}`}
onClick = {() =>{
if(isDisabled) {
return
}
else {
onPageChange(activePage - 1)
}
}
}
>
<ChevronLeft size = {'16px'} className = {`text-sm rounded-md h-4 w-4 ${
isDisabled ? "text-gray-400 cursor-not-allowed" : "text-gray-500 hover:bg-gray-100"}`}/>
</button>
)
}
export default PaginationPrevious
// PaginationNext.tsx
import React from 'react'
import { usePagination } from './PaginationContext'
import { ChevronRight } from 'lucide-react'
const PaginationNext = () => {
const {totalPages, activePage, onPageChange} = usePagination();
const isDisabled = activePage === totalPages
return (
<button
disabled = {isDisabled}
className = {`text-sm font-medium rounded-md h-7 w-7 flex justify-center items-center ml-2 ${
isDisabled ? "text-gray-300 cursor-not-allowed" : "text-gray-500 hover:bg-gray-100"}`}
onClick = {() =>{
if(isDisabled) {
return
}
else {
onPageChange(activePage + 1)
}
}
}
>
<ChevronRight size = {'16px'} className = {`text-sm rounded-md h-4 w-4 ${
isDisabled ? "text-gray-400 cursor-not-allowed" : "text-gray-500 hover:bg-gray-100"}`}/>
</button>
)
}
export default PaginationNext