@choice-ui/pagination
v0.0.3
Published
A pagination component for navigating through paginated data with page numbers and controls
Downloads
220
Readme
Pagination
An advanced pagination component with compound components for flexible layouts, supporting page navigation, page size selection, and direct page input.
Features
- Compound Components: Flexible composition with
Pagination.Spinner,Pagination.Navigation, andPagination.ItemsPerPage - Smart Navigation: Intelligent page number display with ellipsis for large datasets
- Page Size Control: Built-in items per page selector using Segmented component
- Direct Page Jump: Input field for quick navigation to specific pages
- Keyboard Support: Full keyboard navigation and shortcuts
- Loading States: Built-in loading state support
- Accessibility: ARIA labels and keyboard navigation
- Customizable Labels: Support for custom text labels and internationalization
- Performance: Optimized with
useMemofor expensive calculations
Installation
npm install @choic-ui/reactBasic Usage
import { Pagination } from "@choic-ui/react"
function App() {
const [currentPage, setCurrentPage] = useState(1)
const [itemsPerPage, setItemsPerPage] = useState(10)
return (
<Pagination
currentPage={currentPage}
totalItems={250}
itemsPerPage={itemsPerPage}
onPageChange={setCurrentPage}
onItemsPerPageChange={setItemsPerPage}
>
<Pagination.Spinner />
<Pagination.Navigation />
<Pagination.ItemsPerPage />
</Pagination>
)
}Compound Components
Pagination.Spinner
Page input with arrow navigation buttons. Allows direct page number input with automatic validation.
<Pagination.Spinner />Features:
- Left/right arrow buttons for previous/next navigation
- Click to edit page number directly
- Enter key to submit, Escape to cancel
- Automatic text selection on focus
- Input validation with min/max boundaries
- Shows current page and total pages
Pagination.Navigation
Number button navigation with intelligent ellipsis display.
<Pagination.Navigation variant={(isActive) => (isActive ? "solid" : "ghost")} />Features:
- Smart page number display with ellipsis
- Active page highlighting
- Customizable button variants
- Responsive to maxPageButtons prop
- Keyboard accessible
Pagination.ItemsPerPage
Page size selector using the Segmented component.
<Pagination.ItemsPerPage options={[10, 25, 50, 100]} />Features:
- Segmented control for size selection
- Custom options support
- Automatic page recalculation on size change
- Can be rendered as custom child component
API Reference
Pagination (Root)
| Prop | Type | Default | Description |
| ---------------------- | -------------------------------- | ----------------------- | ----------------------------------------- |
| currentPage | number | - | Current active page (1-indexed) |
| totalItems | number | - | Total number of items |
| itemsPerPage | number | 10 | Number of items per page |
| onPageChange | (page: number) => void | - | Callback when page changes |
| onItemsPerPageChange | (itemsPerPage: number) => void | - | Callback when items per page changes |
| maxPageButtons | number | 7 | Maximum number of page buttons to display |
| pageSizeOptions | number[] | [10, 20, 30, 50, 100] | Available page size options |
| disabled | boolean | false | Disable all interactions |
| loading | boolean | false | Show loading state |
| labels | Partial<PaginationLabels> | - | Custom text labels |
| showPageSizeSelector | boolean | true | Show page size selector |
PaginationLabels
interface PaginationLabels {
page: string // Default: "Page"
}Examples
Basic Pagination
<Pagination
currentPage={currentPage}
totalItems={100}
onPageChange={setCurrentPage}
>
<Pagination.Navigation />
</Pagination>Full Featured
<Pagination
currentPage={currentPage}
totalItems={500}
itemsPerPage={itemsPerPage}
onPageChange={setCurrentPage}
onItemsPerPageChange={setItemsPerPage}
>
<Pagination.Spinner />
<Pagination.Navigation />
<Pagination.ItemsPerPage />
</Pagination>Custom Layout
<Pagination
currentPage={currentPage}
totalItems={1000}
onPageChange={setCurrentPage}
>
<div className="flex w-full justify-between">
<Pagination.ItemsPerPage />
<Pagination.Navigation />
<Pagination.Spinner />
</div>
</Pagination>With Custom Labels (i18n)
<Pagination
currentPage={currentPage}
totalItems={250}
onPageChange={setCurrentPage}
labels={{
first: "�u",
last: "+u",
previous: "
�u",
next: "�u",
page: "u",
of: "q",
items: "a",
itemsPerPage: "a/u"
}}
>
<Pagination.Navigation />
</Pagination>Disabled State
<Pagination
currentPage={1}
totalItems={100}
disabled={true}
onPageChange={setCurrentPage}
>
<Pagination.Navigation />
</Pagination>Loading State
<Pagination
currentPage={currentPage}
totalItems={totalItems}
loading={isLoading}
onPageChange={setCurrentPage}
>
<Pagination.Navigation />
</Pagination>Custom Page Size Options
<Pagination
currentPage={currentPage}
totalItems={1000}
itemsPerPage={25}
pageSizeOptions={[25, 50, 100, 200]}
onPageChange={setCurrentPage}
onItemsPerPageChange={setItemsPerPage}
>
<Pagination.ItemsPerPage />
<Pagination.Navigation />
</Pagination>Minimal Navigation
<Pagination
currentPage={currentPage}
totalItems={50}
maxPageButtons={5}
onPageChange={setCurrentPage}
>
<Pagination.Navigation />
</Pagination>Custom Navigation Variants
<Pagination
currentPage={currentPage}
totalItems={200}
onPageChange={setCurrentPage}
>
<Pagination.Navigation variant={(isActive) => (isActive ? "primary" : "secondary")} />
</Pagination>Server-Side Pagination
function TableWithPagination() {
const [page, setPage] = useState(1)
const [pageSize, setPageSize] = useState(20)
const { data, isLoading } = useQuery({
queryKey: ["items", page, pageSize],
queryFn: () => fetchItems({ page, pageSize }),
})
return (
<>
<Table data={data?.items} />
<Pagination
currentPage={page}
totalItems={data?.total || 0}
itemsPerPage={pageSize}
loading={isLoading}
onPageChange={setPage}
onItemsPerPageChange={setPageSize}
>
<Pagination.Spinner />
<Pagination.Navigation />
<Pagination.ItemsPerPage />
</Pagination>
</>
)
}URL State Synchronization
function PaginatedList() {
const [searchParams, setSearchParams] = useSearchParams()
const page = parseInt(searchParams.get("page") || "1")
const pageSize = parseInt(searchParams.get("pageSize") || "20")
const handlePageChange = (newPage: number) => {
setSearchParams((prev) => {
prev.set("page", newPage.toString())
return prev
})
}
const handlePageSizeChange = (newPageSize: number) => {
setSearchParams((prev) => {
prev.set("pageSize", newPageSize.toString())
prev.set("page", "1") // Reset to first page
return prev
})
}
return (
<Pagination
currentPage={page}
totalItems={1000}
itemsPerPage={pageSize}
onPageChange={handlePageChange}
onItemsPerPageChange={handlePageSizeChange}
>
<Pagination.Navigation />
<Pagination.ItemsPerPage />
</Pagination>
)
}Keyboard Shortcuts
Pagination.Spinner
Click- Enter edit modeEnter- Submit page numberEscape- Cancel editingArrow Left/Right- Navigate pages (via buttons)
Pagination.Navigation
Tab- Navigate between page buttonsEnter/Space- Select page
Styling
The component uses Tailwind Variants for styling. Key style configurations:
// Size variants
size: {
default: "text-body",
large: "text-body-medium"
}
// Button variants (Navigation)
variant: (isActive: boolean) => isActive ? "solid" : "ghost"
// Spinner styles
- Arrow buttons with rounded corners
- Input field with border highlight on focus
- Seamless integration with button groupAccessibility
- ARIA Labels: All interactive elements have proper ARIA labels
- Keyboard Navigation: Full keyboard support for all interactions
- Focus Management: Proper focus states and tab order
- Screen Reader Support: Announces page changes and current state
- aria-current: Active page marked with
aria-current="page" - Disabled States: Proper disabled state handling for boundaries
Architecture
File Structure
pagination/
├── components/
│ ├── pagination-root.tsx # Root compound component
│ ├── pagination-spinner.tsx # Page input with arrows
│ ├── pagination-navigation.tsx # Number buttons
│ ├── pagination-items-per-page.tsx # Page size selector
│ └── pagination-context.tsx # Shared context provider
├── hooks/
│ └── use-pagination.ts # Core pagination logic
├── utils/
│ └── pagination-helpers.ts # Utility functions
├── types.ts # TypeScript definitions
├── tv.ts # Tailwind Variants styles
├── pagination.tsx # Main export
└── index.ts # Public exportsDesign Patterns
- Compound Components: Flexible composition pattern
- Context API: Shared state between sub-components
- Custom Hooks: Reusable pagination logic
- Tailwind Variants: Type-safe styling system
- Performance Optimization: Memoized calculations
Best Practices
- Always provide totalItems: Required for calculating total pages
- Controlled component: Always handle
onPageChangecallback - Page size changes: Handle
onItemsPerPageChangewhen using ItemsPerPage - Loading states: Use
loadingprop during data fetching - Internationalization: Provide custom labels for non-English interfaces
- Responsive design: Consider using compact mode for mobile layouts
- URL synchronization: Keep pagination state in URL for shareable links
- Debouncing: Consider debouncing rapid page changes for server requests
Browser Support
- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
- Opera 76+
Related Components
- Table - Often used with pagination
- List - Can be paginated
- VirtualizedGrid - Alternative for large datasets
