Amplify UI

Pagination

Pagination allows users to navigate large sets of data.

Demo

Usage

Import the Pagination component. To use Pagination as an uncontrolled component, import the usePagination hook and pass it an object including the following properties:

  • totalPages (required)
  • currentPage (optional, defaults to 1)
  • siblingCount (optional, defaults to 1)
  • hasMorePages (optional)
import { Pagination, usePagination } from '@aws-amplify/ui-react';

export const DefaultPaginationExample = () => {
  const paginationProps = usePagination({ totalPages: 8 });

  return <Pagination {...paginationProps} />;
};

Controlled component

To use Pagination as a controlled component, you'll need to handle state using these callback functions:

  • onNext: triggered when the next-page button > is pressed
  • onPrevious: triggered when the previous-page button < is pressed
  • onChange: triggered every time the page changes (e.g., when a page button is pressed directly)
import * as React from 'react';
import { Pagination } from '@aws-amplify/ui-react';

export const ControlledPaginationExample = () => {
  const [currentPageIndex, setCurrentPageIndex] = React.useState(1);
  const totalPages = 5;

  const handleNextPage = () => {
    console.log('handleNextPage');
    setCurrentPageIndex(currentPageIndex + 1);
  };

  const handlePreviousPage = () => {
    console.log('handlePreviousPage');
    setCurrentPageIndex(currentPageIndex - 1);
  };

  const handleOnChange = (newPageIndex, prevPageIndex) => {
    console.log(
      `handleOnChange \n - newPageIndex: ${newPageIndex} \n - prevPageIndex: ${prevPageIndex}`
    );
    setCurrentPageIndex(newPageIndex);
  };

  return (
    <Pagination
      currentPage={currentPageIndex}
      totalPages={totalPages}
      onNext={handleNextPage}
      onPrevious={handlePreviousPage}
      onChange={handleOnChange}
    />
  );
};

Paginating at an API level

It's common to use a paged API where the total number of pages in the dataset is unknown until you've reached the final page. To use the Pagination component in this scenario, set the totalPages prop to the total pages of content loaded from the API so far, and set hasMorePages initially to true (which enables the next button to be clicked to trigger another API call). Update the totalPages as you fetch more data. Once you reach the end of the data, set the hasMorePages to false (and thus the Pagination component's next button will be disabled). See below for a contrived example:

import * as React from 'react';
import { Pagination } from '@aws-amplify/ui-react';

export const PaginationHasMorePagesExample = () => {
  const [pageTokens, setPageTokens] = React.useState(['page2']);
  const [currentPageIndex, setCurrentPageIndex] = React.useState(1);
  const [hasMorePages, setHasMorePages] = React.useState(true);

  const handleNextPage = async () => {
    if (hasMorePages && currentPageIndex === pageTokens.length) {
      const { nextToken } = await myAPI.fetch();

      if (!nextToken) {
        setHasMorePages(false);
      }

      setPageTokens([...pageTokens, nextToken]);
    }

    setCurrentPageIndex(currentPageIndex + 1);
  };

  return (
    <Pagination
      currentPage={currentPageIndex}
      totalPages={pageTokens.length}
      hasMorePages={hasMorePages}
      onNext={handleNextPage}
      onPrevious={() => setCurrentPageIndex(currentPageIndex - 1)}
      onChange={(pageIndex) => setCurrentPageIndex(pageIndex)}
    />
  );
};

const mockedAPI = () => {
  const response = [
    {
      res: 'cat',
      nextToken: 'page3',
    },
    {
      res: 'parrot',
      nextToken: null,
    },
  ];

  let timesCalled = 0;

  return {
    fetch() {
      if (timesCalled < 2) {
        return response[timesCalled++];
      }
    },
  };
};

const myAPI = mockedAPI();

Sibling Count

siblingCount is an optional prop which controls the number of pages displayed on each side of the current page (defaults to 1). For example, in the demo below, notice how page 5 has two siblings to the left (3 and 4) and two siblings to the right (6 and 7).

import { Pagination, usePagination } from '@aws-amplify/ui-react';

export const PaginationSiblingCountExample = () => {
  const paginationProps = usePagination({
    totalPages: 11,
    currentPage: 5,
siblingCount: 2,
}); return <Pagination {...paginationProps} />; };

Accessibility

Accessible labels are provided for the Pagination buttons either via the aria-label attribute or by using the VisuallyHidden primitive.

Use the following props to customize these labels:

  • previousLabel: Set the aria-label for the previous page button (defaults to Go to previous page)

  • nextLabel: Set the aria-label for the next page button (defaults to Go to next page)

  • currentPageLabel: Set the VisuallyHidden label for current page (defaults to Page). This will be used to construct the label text for current page. e.g, Page: 1 if page 1 is the current page.

  • pageLabel: Set the label for each page button other than the current page (defaults to Go to page). This will be used to construct the aria-label. e.g, Go to page 1 for page 1 button.

By default, the root node of the Pagination component is a <nav> element. Elements with the navigation role, like <nav>, require unique labels if there are multiple on the same page. Passing an aria-label to the Pagination component is one way to accomodate this.

import { usePagination, Pagination } from '@aws-amplify/ui-react';

export const PaginationAccessibilityExample = () => {
  const paginationProps = usePagination({ totalPages: 5 });
  return (
    <Pagination
      aria-label="Example pagination"
      pageLabel="Jump to page"
      currentPageLabel="You are on page"
      previousLabel="Back to previous page"
      nextLabel="Forward to next page"
      {...paginationProps}
    />
  );
};

Styling

Theme

You can customize the appearance of all Pagination components in your application with a Theme.

Pagination Theme Source

import {
  Pagination,
  usePagination,
  ThemeProvider,
  Theme,
} from '@aws-amplify/ui-react';

const theme: Theme = {
  name: 'pagination-theme',
  tokens: {
    components: {
      pagination: {
        current: {
          backgroundColor: { value: '{colors.secondary.80}' },
        },
        button: {
          hover: {
            backgroundColor: { value: '{colors.neutral.40}' },
            color: { value: '{colors.secondary.80}' },
          },
        },
      },
    },
  },
};

export const PaginationThemeExample = () => {
  const paginationProps = usePagination({ totalPages: 6 });

  return (
    <ThemeProvider theme={theme} colorMode="light">
      <Pagination {...paginationProps} />
    </ThemeProvider>
  );
};

Icons

import {
  Pagination,
  usePagination,
  IconsProvider,
} from '@aws-amplify/ui-react';
import { FiArrowLeft, FiArrowRight } from 'react-icons/fi';

export const PaginationIconExample = () => {
  const paginationProps = usePagination({ totalPages: 6 });

  return (
    <IconsProvider
      icons={{
        pagination: {
          next: <FiArrowRight />,
          previous: <FiArrowLeft />,
        },
      }}
    >
      <Pagination {...paginationProps} />
    </IconsProvider>
  );
};

Target classes

ClassDescription
amplify-paginationTop level element that wraps the Pagination primitive
amplify-pagination__itemClass applied to the pagination items
  • --amplify-components-pagination-button-color
  • --amplify-components-pagination-button-disabled-color
  • --amplify-components-pagination-button-hover-background-color
  • --amplify-components-pagination-button-hover-color
  • --amplify-components-pagination-button-padding-inline-end
  • --amplify-components-pagination-button-padding-inline-start
  • --amplify-components-pagination-button-transition-duration
  • --amplify-components-pagination-button-transition-property
  • --amplify-components-pagination-current-align-items
  • --amplify-components-pagination-current-background-color
  • --amplify-components-pagination-current-color
  • --amplify-components-pagination-current-font-size
  • --amplify-components-pagination-current-justify-content
  • --amplify-components-pagination-ellipsis-align-items
  • --amplify-components-pagination-ellipsis-justify-content
  • --amplify-components-pagination-ellipsis-padding-inline-end
  • --amplify-components-pagination-ellipsis-padding-inline-start
  • --amplify-components-pagination-item-container-margin-left
  • --amplify-components-pagination-item-container-margin-right
  • --amplify-components-pagination-item-shared-border-radius
  • --amplify-components-pagination-item-shared-height
  • --amplify-components-pagination-item-shared-min-width

Global styling

To override styling on all Pagination components, you can set the Amplify CSS variables or use the built-in .amplify-pagination class.

/* styles.css */
.amplify-pagination {
  --amplify-components-pagination-current-background-color: var(
    --amplify-colors-red-60
  );
}
import { Pagination, usePagination } from '@aws-amplify/ui-react';
import './styles.css';

const PaginationGlobalStylingExample = () => {
  const paginationProps = usePagination({ totalPages: 8 });
  return <Pagination {...paginationProps} />;
};

Local styling

To override styling on a specific Pagination component, you can use a class selector or style props.

Using a class selector:

/* styles.css */
.my-custom-pagination {
  --amplify-components-pagination-current-background-color: var(
    --amplify-colors-green-80
  );
  --amplify-components-pagination-button-hover-background-color: var(
    --amplify-colors-blue-20
  );
}
import { Pagination, usePagination } from '@aws-amplify/ui-react';
import './styles.css';

const PaginationClassStylingExample= () => {
  const paginationProps = usePagination({ totalPages: 7 });
  return <Pagination {...paginationProps} className="my-custom-pagination" />;
};

Using style props:

import { Pagination, usePagination } from '@aws-amplify/ui-react';

const PaginationStylePropsExample = () => {
  const paginationProps = usePagination({ totalPages: 5 });
  return <Pagination {...paginationProps} backgroundColor="lavender" padding="1rem" />;
};

Amplify open source software, documentation and community are supported by Amazon Web Services.

© 2024 Amazon Web Services, Inc. and its affiliates. All rights reserved. View the site terms and privacy policy.

Flutter and the related logo are trademarks of Google LLC. We are not endorsed by or affiliated with Google LLC.