Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Navigation

Pagination

Navigation

Pagination React component for Tailwind CSS v4

Nav TabsProximity Sidebar
Live props
State
defaultPage1
defaultPageSize
loading
disabled
Appearance
variant
size
activeVariant
radius
tone
color
Layout
mobileVariant
siblingCount1
boundaryCount1
align
Content
showFirstLast
showSummary
showPageSize
showJump
Behavior
autoLoad
locale
Code
import { Pagination } from "@/components/ui/pagination"

<Pagination />
  1. Home
  2. Components
  3. Navigation
  4. Pagination
Pro

Pagination React component for Tailwind CSS v4

v1.0.0·Added in 1.0.0

A React pagination for tables and lists: numbered pages with ellipses, previous / next, page size, jump to page and load more.

Click a page number and the current-page pill slides to it on a quick spring; previous and next step one page and grey out at the ends, the optional « » buttons jump to the first and last page. With the keyboard, Tab reaches every control, and while focus is on the pages Left / Right go to the previous / next page and keep focus on the new current page, Home / End jump to the first / last. Type a number in "Go to" and press Enter to jump (it clamps to the real range). The page size select keeps the first row you were looking at on screen. The summary ("21 to 40 of 318") is announced once per change. When it is narrower than 640px (a phone, a card, a side panel) it becomes ‹ Page 5 of 16 › with the summary under the text: tap it for a list of every page (a bottom sheet on phones); buttons are 44px on touch. The load-more variant shows how many are left and a thin progress bar, and with autoLoad it loads on its own when you scroll within 200px of it.

Pagination is a Pro React component in the React navigation components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add pagination, together with Button, Field, Select, useControllableState, useLocale and 6 more and the npm packages motion and lucide-react.

Add to a project

Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add pagination

Pagination is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans

Usage

Import Pagination from @/components/ui/pagination.

import { useState } from "react"
import { Pagination } from "@/components/ui/pagination"

export function InvoicesFooter({ total }: { total: number }) {
  const [page, setPage] = useState(1)
  const [pageSize, setPageSize] = useState(20)
  return (
    <Pagination
      total={total}
      page={page}
      onPageChange={setPage}
      pageSize={pageSize}
      onPageSizeChange={setPageSize}
      showPageSize
      locale="en-US"
      labels={{
        summary: (a, b, t) => `${a}\u2013${b} of ${t} invoices`,
        pageSize: "Invoices per page",
      }}
    />
  )
}

Props

  • page
    number

    The current page, 1-based, controlled. A page beyond pageCount renders as given with next disabled; it is never corrected silently.

  • defaultPagedefault 1
    number

    The starting page while uncontrolled.

  • onPageChange
    (page: number) => void

    Fires on every page change: a click, an arrow key, the jump field, the compact page picker or a page size change.

  • pageCount
    number

    Total pages. Default: ceil(total / pageSize). 0 renders only the summary ("No results").

  • total
    number

    The item count, for the page count and the summary ("1 to 20 of 318"). Without it the summary reads "Page 5 of 16".

  • pageSize
    number

    Items per page, controlled.

  • defaultPageSizedefault "20"
    number

    Items per page while uncontrolled; also used when total is given without pageSize.

  • onPageSizeChange
    (pageSize: number) => void

    Fires when the page size select changes. The page moves so the first visible item stays on screen: page = floor(firstIndex / newSize) + 1.

  • pageSizeOptionsdefault "[10, 20, 50, 100]"
    number[]

    The choices in the page size select.

  • variantdefault "numbers"
    "numbers" | "simple" | "compact" | "load-more"

    numbers: ‹ 1 … 4 5 6 … 20 ›. simple: Previous / Next buttons with the summary between. compact: ‹ Page 5 of 20 › where the text opens a page picker. load-more: a full-width button for feeds with a remaining count and a progress bar.

  • mobileVariantdefault "compact"
    "compact" | "simple" | "numbers"

    What renders while the pagination is narrower than 640px: a phone, or a card or side panel on desktop (a CSS container query). Both layouts are in the server HTML and CSS picks one, so nothing jumps after hydration. numbers drops the sibling pages there so it fits 360px.

  • siblingCountdefault 1
    number

    Pages shown on each side of the current one. The slots come from getPageRange(page, pageCount, siblingCount, boundaryCount), exported for custom UIs; their count stays constant while the page moves.

  • boundaryCountdefault 1
    number

    Pages always shown at each end.

  • showFirstLastdefault false
    boolean

    Adds « and » buttons that jump to the first and last page. Below 640px the numbers row drops them (its boundary pages already reach the ends) so it fits 360px.

  • showSummarydefault true
    boolean

    Shows "1 to 20 of 318" (a polite live region, so screen readers hear each change once).

  • showPageSizedefault false
    boolean

    Shows the page size select ("20 per page"); a bottom sheet on phones.

  • showJumpdefault false
    boolean

    Shows a small "Go to" number field: Enter jumps, out-of-range numbers clamp. Hidden on phones when the compact picker is there.

  • aligndefault "between"
    "start" | "center" | "end" | "between"

    between puts the summary at the start and the pages at the end; the others keep them together.

  • sizedefault "md"
    "sm" | "md" | "lg"

    Button height 32 / 40 / 48px (md is 44px on touch). Page buttons are square and grow for long numbers.

  • activeVariantdefault "soft"
    "soft" | "solid" | "outline"

    The current page's pill: a soft tint (like tabs), the solid tone fill, or an outline.

  • radiusdefault "md"
    "none" | "sm" | "md" | "lg" | "full"

    Corner shape of every button, scaled with the size like the button's; full makes round page pills.

  • tonedefault "neutral"
    "neutral" | "brand" | "success" | "warning" | "danger" | "info"

    The current page's color (and the load-more button and bar). Neutral is black in light mode and white in dark mode.

  • colordefault ""
    string

    Any CSS color for the current page; replaces the tone. Leave empty to use the tone.

  • loadingdefault false
    boolean

    The next page is loading: the control you pressed shows a spinner and the rest are disabled until it turns false.

  • disableddefault false
    boolean

    Dims and blocks every control.

  • autoLoaddefault false
    boolean

    load-more only: loads the next batch on its own when the button scrolls within 200px (IntersectionObserver in the nearest scroll container).

  • localedefault ""
    string

    Number formatting ("1.250" in de-DE, "1,250" in en-US). Empty uses the LocaleProvider, then the page language.

  • getPageHref
    (page: number) => string

    Renders every page as a link (NavLink through the app's router link) instead of a button: crawlable, open in a new tab, router-friendly. Arrow keys, the jump field and the page picker navigate too.

  • linkComponent
    (props: LinkComponentProps) => ReactNode

    The link component for this instance; default the LinkProvider's, else a plain <a>.

  • hasNextPage
    boolean

    Cursor pagination without a known count: when set and neither total nor pageCount is, only previous / next render, next disabled when false.

  • hasMore
    boolean

    load-more: whether there is more to load. Default loadedCount < total. false shows the end message.

  • onLoadMore
    (() => void | Promise<unknown>)

    load-more: called by the button (or autoLoad). Return a promise to show the loading state until it settles.

  • loadedCount
    number

    load-more: items already on screen, for "Showing 40 of 318", the remaining count and the bar.

  • labels
    Partial<PaginationLabels>

    Every string, English by default: navigation, previous, next, first, last, page(n), pageOf(page, count), summary(from, to, total), empty, pageSize, perPage(size), jump, loadMore(count), remaining(count), loading, end, showing(shown, total). Numbers arrive formatted for the locale. DEFAULT_PAGINATION_LABELS is exported to spread and override.

  • classNames
    Partial<Record<"meta" | "summary" | "controls" | "list" | "item" | "link" | "ellipsis" | "indicator" | "previous" | "next" | "first" | "last" | "size" | "jump" | "compact" | "loadMore" | "loadMoreStatus" | "loadMoreBar", string>>

    Extra classes for the inner parts.

Parts

  • getPageRange

    function

    getPageRange(page, pageCount, siblingCount = 1, boundaryCount = 1): the visible slots, like [1, "start-ellipsis", 4, 5, 6, "end-ellipsis", 20], for building your own pager.

  • DEFAULT_PAGINATION_LABELS

    constant

    The English strings: previous, next, first, last, the summary, page size, jump, load more and the screen reader page names. Override keys through labels.

  • PaginationRangeItem

    type

    One slot from getPageRange: a page number, "start-ellipsis" or "end-ellipsis".

  • PaginationProps

    type

    The props of Pagination, for wrappers that connect it to your router or data hook.

Examples

Four variants

numbers, simple, compact and load-more, the same data.

Admin table footer

Page size, jump to page and first / last buttons. Changing the size keeps your first row on screen.

Pages as links

getPageHref renders real links through the router: crawlable and fine in a new tab. The address bar follows.

Load more in a feed

autoLoad loads before you reach the end; the bar and the remaining count follow.

Cursor pagination

No total, just hasNextPage: only previous and next, with a spinner on the one you pressed.

Sizes, radius and color

32, 40 and 48px, a brand solid pill and an outlined custom color.

ro-RO and en-US

The same 24,980 results formatted for each locale.

Dependencies

motionlucide-reactbuttonfieldselectuse-controllable-stateuse-localeuse-scroll-statemotionnavigationnumber-formattonesui-config

Files

  • components/ui/pagination.tsx

FAQ

Is the React Pagination component free?

The preview, props and docs are free; copying the source needs a Pro plan. See plans.

How do I install Pagination?

Run npx wingo-ui@latest add pagination. It also adds the Wingo UI items it builds on (Button, Field, Select, useControllableState, useLocale and 6 more) and the npm packages motion and lucide-react. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/pagination.

How does Pagination behave on phones?

When it is narrower than 640px (a phone, a card, a side panel) it becomes ‹ Page 5 of 16 › with the summary under the text: tap it for a list of every page (a bottom sheet on phones); buttons are 44px on touch.

See also

Data TableTableToolbarButton GroupSelect

Used in

Listing gridData TableReviewsBlog PageChangelog Page

More React navigation components

StepsTable Of ContentsTabsTopbarWorkspace SwitcherBreadcrumb
All 19 React navigation components

Articles using this component

  • TanStack Table v9 Data Table: Filters, Bulk Actions, Mobile

    Component guides · Oct 9, 2026 · 12 min read

PreviousNav TabsNext Proximity Sidebar
Issued invoicesAcme CRM · 2026
page=1 pageSize=20 locale=en-US
  • #2026-0318
    Summit Logistics Inc.#2026-0318 · 09/23/2026Denver
    09/23/2026Overdue
    $7,222.66Overdue
  • #2026-0317
    BuildRight Group LLC#2026-0317 · 09/23/2026Seattle
    09/23/2026Issued
    $13,903.29Issued
  • #2026-0316
    Westside Books#2026-0316 · 09/22/2026Chicago
    09/22/2026Issued
    $5,984.92Issued
  • #2026-0315
    Carter Design Studio#2026-0315 · 09/21/2026Boston
    09/21/2026Overdue
    $12,665.55Overdue
  • #2026-0314
    Old Mill Bakery LLC#2026-0314 · 09/20/2026Madison
    09/20/2026Issued
    $4,746.18Issued
  • #2026-0313
    Tech Solutions LLC#2026-0313 · 09/19/2026Austin
    09/19/2026Issued
    $11,427.81Issued
  • #2026-0312
    Wellness Pharmacy#2026-0312 · 09/18/2026Portland
    09/18/2026Overdue
    $3,508.44Overdue
  • #2026-0311
    Dental Art Clinic#2026-0311 · 09/18/2026Miami
    09/18/2026Issued
    $10,189.07Issued
  • #2026-0310
    Summit Logistics Inc.#2026-0310 · 09/17/2026Denver
    09/17/2026Issued
    $2,270.70Issued
  • #2026-0309
    BuildRight Group LLC#2026-0309 · 09/16/2026Seattle
    09/16/2026Overdue
    $8,951.33Overdue
  • #2026-0308
    Westside Books#2026-0308 · 09/15/2026Chicago
    09/15/2026Issued
    $1,032.96Issued
  • #2026-0307
    Carter Design Studio#2026-0307 · 09/14/2026Boston
    09/14/2026Issued
    $7,713.59Issued
  • #2026-0306
    Old Mill Bakery LLC#2026-0306 · 09/13/2026Madison
    09/13/2026Overdue
    $14,394.22Overdue
  • #2026-0305
    Tech Solutions LLC#2026-0305 · 09/13/2026Austin
    09/13/2026Issued
    $6,475.85Issued
  • #2026-0304
    Wellness Pharmacy#2026-0304 · 09/12/2026Portland
    09/12/2026Issued
    $13,156.48Issued
  • #2026-0303
    Dental Art Clinic#2026-0303 · 09/11/2026Miami
    09/11/2026Overdue
    $5,237.11Overdue
  • #2026-0302
    Summit Logistics Inc.#2026-0302 · 09/10/2026Denver
    09/10/2026Issued
    $11,918.74Issued
  • #2026-0301
    BuildRight Group LLC#2026-0301 · 09/09/2026Seattle
    09/09/2026Issued
    $3,999.37Issued
  • #2026-0300
    Westside Books#2026-0300 · 09/08/2026Chicago
    09/08/2026Paid
    $10,680.00Paid
  • #2026-0299
    Carter Design Studio#2026-0299 · 09/08/2026Boston
    09/08/2026Paid
    $2,761.63Paid

1–20 of 318

  • …