Open-source project
react-component/pagination avatar
react-component/pagination

rc-component/pagination: the pagination primitive Ant Design itself uses

📄 React pagination primitives for page navigation, size changing, quick jumping, and locale-aware controls.

674 stars334 forksTypeScriptMIT

At a glance

What is it?
@rc-component/pagination is the headless React pagination component behind Ant Design's own Pagination, published on npm with controlled and uncontrolled state, a size changer, a quick jumper, locale packages and item level class names. It is a component rather than a design system, so you supply the styling.
Who is it for?
rc-component/pagination suits a team that wants Ant Design's pagination behaviour without Ant Design's visual language, or that already depends on the rc-component family and wants its APIs and release cadence to line up.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A primitive, not a widget, and Ant Design is its first customer

The package describes itself as React pagination primitives for page navigation, size changing, quick jumping and locale-aware controls, and the README states plainly that it is used by Ant Design as the shared pagination foundation. The Ant Design ecosystem badge at the top of the README is not decoration: it is the reason the component exists and the reason its behaviour is as settled as it is.

That relationship explains both the strength and the limit of the package. Ant Design has thousands of users and a large surface for a pagination control to be wrong about: the number of items shown when the total is large, the behaviour when the current page is deleted, the interaction between the size changer and the jumper, the rendering of a disabled page, the keyboard focus order. All of that is already solved here, and the component is MIT licensed with a LICENSE file and a LICENSE.md at the root.

The limit is that a primitive is not a component library entry. You get behaviour and a set of hooks, and you bring the visuals. The package ships a stylesheet and Less source, and the README's usage example imports the CSS explicitly, so even the base styling is something you opt into and can override.

The audience is a React team that wants this particular behaviour and is prepared to own the appearance. If you are already using Ant Design, this is what you are using under the hood and you probably want the Ant Design wrapper. If you are not, you are taking the behaviour and writing the theme.

Controlled and uncontrolled state is the decision you make on day one

The first item on the highlights list is controlled and uncontrolled pagination state, and it is the most consequential choice in the API.

The uncontrolled path is the smallest example in the README.

tsx
import Pagination from '@rc-component/pagination';
import '@rc-component/pagination/assets/index.css';
export default () => (
  <Pagination defaultCurrent={1} total={120} showSizeChanger showQuickJumper />
);

With defaultCurrent and defaultPageSize, the component keeps the current page internally, and you never have to think about it. The default page size is 10, and the default current page is 1.

The controlled path is the one to look at, because it shows what you take on.

tsx
import Pagination from '@rc-component/pagination';
import enUS from '@rc-component/pagination/locale/en_US';
export default () => (
  <Pagination
    defaultCurrent={2}
    total={500}
    locale={enUS}
    showTotal={(total, range) => `${range[0]}-${range[1]} of ${total} items`}
  />
);

Two things are worth pulling out of that example. The locale is imported as a module from a locale subpath rather than being configured inline, which is how translations are added. And showTotal is a render function that receives the total and the range of items currently on screen, so the summary text is computed by you rather than by a fixed string in the library.

The trade-off in choosing controlled state is that you now own the current page and the page size, and you have to keep them consistent when the data behind the list changes underneath. If the total shrinks because a filter was applied and the current page is now out of range, that is a bug in your code. The uncontrolled path avoids that class of problem entirely, which is why it is the form most small applications should start with.

Either way, this is a decision you make once and it propagates into every call site, which is why it belongs at the top of an evaluation.

Item level class names are how you theme it without forking it

The API table is where the component stops being generic and becomes specific, and two props stand out for anyone who wants to restyle it.

The first is classNames, typed as a Partial<Record<'item', string>>. That is a semantic class name map scoped to the item level, which is a different thing from the className prop, which sets the class name for the root element. The distinction matters: with className alone you can only target the whole control from the outside, while with classNames you can target individual parts, and the record key of 'item' is the semantic slot the library exposes.

Alongside it there is a styles prop with the same idea, and the highlights list names the pair as semantic classNames and styles for item-level customization. Semantic is the important qualifier. The library is telling you it has a fixed internal structure and is giving you named hooks into it, which is a contract you can rely on.

The second prop is itemRender, typed as (page, type, element) => ReactNode, described as the way to customize the page, previous, next and jump items. The signature tells you the mechanism: you get the page number, the type of element being rendered, and the default element, and you return a node. That is a replace-the-default escape hatch rather than a style override, so it can be used to change the markup of a specific item, not just its class.

The jump icons are handled separately with jumpNextIcon and jumpPrevIcon, each accepting a ReactNode or a ComponentType. Those exist because the quick jumper's next and previous controls are not the same as the page navigation controls, and a design system usually wants different icons for the two.

The other notable props in the visible part of the table are the straightforward ones: align with start, center or end, disabled, hideOnSinglePage, and the showTotal render function. The type definitions for props, locale, callbacks and state are listed in the highlights, and the project ships TypeScript definitions for all of them.

Locale packages are separate entry points, and they are not optional

Locale is a first class concern in this package rather than a prop you fill in, and the mechanism is a set of subpath exports.

The highlights list names locale packages exposed from @rc-component/pagination/locale/*. The usage example imports enUS from '@rc-component/pagination/locale/en_US'. The package manifest then shows the plumbing: the exports map has entries for ./locale/*, ./lib/locale/* and ./es/locale/*, each with its own types, import and require conditions.

The duplication of those three subpaths is a packaging detail rather than a design choice, and it comes from the build layout. The manifest shows main pointing at ./lib/index for CommonJS, module at ./es/index for bundlers and types at ./es/index.d.ts, and the exports map gives every consumer the right condition for their module system. The locale packages are then exposed from all three trees so that a deep import of a locale file resolves the same way as the main entry point.

The practical advice is straightforward. If your application has a language switcher, the locale module has to be loaded for each language, and the bundler will include only the ones you import. Importing every locale eagerly is a real bundle cost, and the subpath structure exists so you can avoid it.

The second usage example shows a showTotal render function producing a summary of the visible range against the total, and it takes a locale prop, so the text inside your custom render function is yours to localise as well. The library localises its own controls; the strings you write are yours.

The build is dumi for docs, father for the package and less for the styles

The repository is a full open source component project, and the toolchain is worth knowing because it explains the shape of the published artefact.

The documentation site is dumi, with a .dumirc.ts at the root and a start script of dumi dev. The README's own instructions to run the local site are npm install followed by npm start, and then to open http://localhost:8000.

bash
npm install
npm start

The package itself is compiled with father, and the compile script also runs lessc to turn assets/index.less into assets/index.css. That is the whole styling story: Less source in, CSS out, and the CSS is what your application imports.

json
    "compile": "father build && lessc assets/index.less assets/index.css",

The published files list confirms the layout, with assets/*.css, assets/*.less, es and lib as the four things that ship. The es tree is the ES module build, the lib tree is CommonJS, and the type definitions sit alongside them.

The test setup is rc-test with jest.config.js at the root, and coverage is the same runner with a flag. The lint script runs eslint over src with several extensions including markdown, which means the documentation examples are linted too, and the formatter is prettier with a .prettierrc. There is a .husky/ directory for git hooks and a CHANGELOG.md.

The docs are also published to a site, at react-component.github.io/pagination, and there is a vercel.json alongside a .fatherrc.js and .fatherrc.ts, so the same repository is configured for both a Vercel deployment and a GitHub Pages one through the gh-pages script.

Where rc-component/pagination is the wrong tool

The first wrong-tool case is a team that wants a styled component. The package provides behaviour and a base stylesheet, and the rest is yours. If your project does not already have a pagination design, you are writing one, and the cost of writing it may exceed the cost of the small amount of logic the package saves you.

The second case is a project that has standardised on a different component library with its own pagination, especially one with accessibility work already done to a particular standard. rc-component/pagination does not document its accessibility behaviour in the visible API, and adopting a primitive means owning the keyboard navigation, focus management, screen reader announcements and ARIA relationships that the component may or may not implement for you. For a public sector or regulated product, that is a decision that needs its own review.

The third case is a project on React 18 or 19 with different rendering expectations, or one that has standardised on a state management library that conflicts with the component's own internal state. The controlled and uncontrolled split means the component holds state internally in one mode, and a team with a single source of truth for the current page will end up in controlled mode whether they like it or not.

On maintenance, the version history is a good sign. The releases are @rc-component/[email protected] from 2026-10-08, 1.5.0 from 2026-07-03 and 1.4.0 from 2026-06-09, and the last push was on 2026-10-14. Three minor releases in four months with commits in between is a component being maintained rather than merely published.

There is one naming wrinkle to watch. The package is published as @rc-component/pagination, while the repository and the older rc-pagination naming are different strings, and the manifest keywords still list antd and react-component. If you are migrating from an older rc-pagination install, check the package name carefully, because the scoped name is the one on npm and in the exports map.

The licence is MIT with a LICENSE file and a LICENSE.md at the root, which is the permissive grant you would expect from a package that Ant Design depends on.

Editorial conclusion

rc-component/pagination suits a team that wants Ant Design's pagination behaviour without Ant Design's visual language, or that already depends on the rc-component family and wants its APIs and release cadence to line up. It does not suit a team that wants a styled component out of the box, since the package ships CSS and Less source but the component itself renders unstyled markup you must theme, and it does not suit a project on a different React version or with different accessibility requirements. Before adopting, read the API table for the props you need, decide between the controlled and uncontrolled state model early because it changes every call site, and check the locale entry point you need exists under @rc-component/pagination/locale before you commit to it.

Frequently asked questions

What is @rc-component/pagination?

It is a set of React pagination primitives for page navigation, size changing, quick jumping and locale-aware controls, and it is used by Ant Design as the shared pagination foundation. The package is published on npm as @rc-component/pagination and is MIT licensed.

How do I install and use the rc-component pagination package?

Install it with npm install @rc-component/pagination, import Pagination from '@rc-component/pagination' and import '@rc-component/pagination/assets/index.css'. The basic usage passes defaultCurrent, total and the showSizeChanger and showQuickJumper flags.

What is the difference between controlled and uncontrolled pagination state?

With defaultCurrent and defaultPageSize the component tracks the current page itself, which is the uncontrolled mode. With the current prop you own the page number and the size, and you are responsible for keeping them consistent when the underlying data changes. The default page size is 10 and the default current page is 1.

How do I customise the appearance of the rc-component pagination?

The classNames prop is typed as a Partial<Record<'item', string>> for item-level semantic class names, alongside a styles prop, while className targets the root element. For deeper changes, itemRender takes (page, type, element) and returns a ReactNode, and jumpNextIcon and jumpPrevIcon accept a ReactNode or a ComponentType.

Which license is rc-component pagination released under?

The package is MIT licensed, with a LICENSE file and a LICENSE.md at the root of the repository. The current published version is 1.6.0, tagged on 2026-10-08.

Official sources

  1. License: MIT
  2. Project website
  3. react-component/pagination on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/react-component-pagination.svg)](https://hysenlabs.com/projects/react-component-pagination)

Was this useful?