What is Pagination in a web page?

Pagination in websites is a way to structure content by grouping it according to a fixed number of elements. Pagination is simply the number of pages displayed on a web page, which is used to separate content and make navigation easier.

Why should you use pagination on your website?

The use of pagination on your site has some advantages.

Let's take a look:

  • Your pages will have less scroll, having less scroll will improve your UX and SEO, as users of your page may get frustrated and abandon the page if they feel that the page has no end.
  • You can find out the exact number of results returned and which page you are on.
  • When users see the total number of results they can estimate the time it will take them to find what they are looking for.
  • Your page will load faster because the web page is smaller, this will improve your SEO.

How to make stunning pagination with CSS and JS

In this section we will take a look at how to create a pagination with CSS and javascript animation like this one:

See the Pen Animated pagination by FrontendPlanet (@FrontendPlanet) on CodePen.

Step 1: Add the necessary HTML

  <div class="pagination">
<span class="pagination__number-indicator"></span>
<button class="pagination__arrow">
<span class="pagination__arrow-half"></span>
<span class="pagination__arrow-half"></span>
</button>
<button class="pagination__number">1</button>
<button class="pagination__number">2</button>
<button class="pagination__number">3</button>
<button class="pagination__number pagination__number--active">4</button>
<button class="pagination__number">5</button>
<button class="pagination__number">6</button>
<button class="pagination__number">7</button>
<button class="pagination__arrow pagination__arrow--right">
<span class="pagination__arrow-half"></span>
<span class="pagination__arrow-half"></span>
</button>
</div>

Pretty self-explanatory, but let's break down what this HTML contains:

  • There is a main div container with the pagination class.
  • An HTML span element to indicate the selected page number with the class pagination__number-indicator.
  • 2 button arrows with class pagination__arrow, and inside that button 2 spans with class pagination__arrow-half, this is necessary to create the hover, click, and disabled state of the arrows.
  • And the rest of the HTML elements are buttons with the class pagination__number, one for each number.

So for now, everything is straightforward, let's take a look at the CSS.

Step 2: Add the CSS

In this one, we will use SCSS, but it is just for convenience, it can be done with just CSS as well.

  • First of all, let's add some SCSS vars that will be reused throughout the page and some CSS to reset and position the pagination on the page:
$arrow-height: 9px;
$arrow-width: 2px;
$interactive-color: #4338CA;
$black-color: #111827;

html,body {
display: grid;
}

html {
height: 100%;
font-family: -apple-system, sans-serif;
color: $black-color;
}

body {
place-content: center;
background-color: #eef2ff;
}

button {
border: none;
background-color: transparent;
cursor: pointer;
}

Now let's add the styles for the main pagination container:

.pagination {
display: flex;
flex-direction: row;
padding: 24px;
border-radius: 6px;
box-shadow: 0px 4px 8px 0px rgba(31, 41, 55, 0.14);
background-color: #fff;
position: relative;
}

After the main container has the styles, let's add the styles for the number indicator span:

.pagination__number-indicator {
position: absolute;
height: 2px;
background-color: $interactive-color;
opacity: 0;
bottom: 38px;
transition: all .2s ease;
}

Now it is the turn of the styles for the number and when the number page is active:

.pagination__number {
font-weight: 600;
font-size: 16px;
color: #D1D5DB;
}

.pagination__number--active {
color: $black-color;
position: relative;
}

.pagination__number {
padding: 16px;
}

To wrap up the CSS styles let's add all the necessary styles for the arrows, the button arrow elements have more complexity as all the animations are done via CSS:

.pagination__arrow  {
padding: 16px;
}

.pagination__arrow--right {
transform: scaleX(-1);
}

.pagination__arrow-half {
width: $arrow-height;
height: $arrow-width;
border-radius: $arrow-width / 2;
background-color: $interactive-color;
display: inline-block;
position: absolute;
transform-origin: 0px;
opacity: 1;
transition: transform .1s ease-in-out, opacity .2s ease-in-out;
}

.pagination__arrow-half:first-child {
transform: translateY(#{$arrow-width / 4}) rotate(-45deg);
}

.pagination__arrow-half:last-child {
transform: translateY(#{-$arrow-width / 4}) rotate(45deg);
}

//States

.pagination__arrow:hover .pagination__arrow-half:first-child {
transform: translateY(#{$arrow-width / 4}) rotate(-30deg);
}
.pagination__arrow:hover .pagination__arrow-half:last-child {
transform: translateY(#{-$arrow-width / 4}) rotate(30deg);
}

.pagination__arrow:active .pagination__arrow-half:first-child,
.pagination__arrow--disabled .pagination__arrow-half:first-child
{
transform: translateY(0) rotate(0);
}
.pagination__arrow:active .pagination__arrow-half:last-child,
.pagination__arrow--disabled .pagination__arrow-half:last-child
{
transform: translateY(0) rotate(0);
}

.pagination__arrow--disabled .pagination__arrow-half:last-child,
.pagination__arrow--disabled .pagination__arrow-half:first-child
{
opacity: .2;
}

.pagination__arrow--disabled {
pointer-events: none;
}

Step 3: Finally add the Javascript

Last but not least let's make the pagination interactive,

To do that we will start with selecting the pagination and the HTML elements from the DOM if there is a pagination element:

const pagination = document.querySelector('.pagination')

if (pagination) {
const paginationNumbers = document.querySelectorAll('.pagination__number')
let paginationActiveNumber = document.querySelector('.pagination__number--active')
const paginationNumberIndicator = document.querySelector('.pagination__number-indicator')
const paginationLeftArrow = document.querySelector('.pagination__arrow:not(.pagination__arrow--right)')
const paginationRightArrow = document.querySelector('.pagination__arrow--right')
}

The next thing to do is to create a function to position the indicator when we hover over the numbers or to highlight which page we are on:

const postionIndicator = (element) => {
const paginationRect = pagination.getBoundingClientRect()
const paddingElement = parseInt(window.getComputedStyle(element, null).getPropertyValue('padding-left'), 10)
const elementRect = element.getBoundingClientRect()
paginationNumberIndicator.style.left = `${elementRect.left + paddingElement - paginationRect.left}px`
paginationNumberIndicator.style.width = `${elementRect.width - paddingElement * 2}px`
if(element.classList.contains('pagination__number--active')) {
paginationNumberIndicator.style.opacity = 1
} else {
paginationNumberIndicator.style.opacity = .2
}
}

After that, let's add 2 other functions, one to disable and enable the arrows, and another one to detect when the pagination reaches the start or the end limit, and then disable the arrow or enable it:

const disableArrow = (arrow, disable) => {
if (
(!disable && !arrow.classList.contains('pagination__arrow--disabled')) ||
(disable && arrow.classList.contains('pagination__arrow--disabled'))
)
return
if (disable) {
arrow.classList.add('pagination__arrow--disabled')
} else {
arrow.classList.remove('pagination__arrow--disabled')
}
}

const setArrowState = () => {
const previousElement = paginationActiveNumber.previousElementSibling
const nextElement = paginationActiveNumber.nextElementSibling
if(previousElement.classList.contains('pagination__number')) {
disableArrow(paginationLeftArrow, false)
} else {
disableArrow(paginationLeftArrow, true)
}

if(nextElement.classList.contains('pagination__number')) {
disableArrow(paginationRightArrow, false)
} else {
disableArrow(paginationRightArrow, true)
}
}

Next, we will add our last function, which is necessary to activate the number when changing pages:

const setActiveNumber = (element) => {
if (element.classList.contains('pagination__number--active')) return
element.classList.add('pagination__number--active')
paginationActiveNumber.classList.remove('pagination__number--active')
paginationActiveNumber = element
setArrowState()
}

After all the functions, let´s add all the necessary events, 1 event for when the 2 arrows are clicked, setting the next or previous number as active and updating the active indicator:

paginationLeftArrow.addEventListener('click', () => {
setActiveNumber(paginationActiveNumber.previousElementSibling)
postionIndicator(paginationActiveNumber)
})

paginationRightArrow.addEventListener('click', () => {
setActiveNumber(paginationActiveNumber.nextElementSibling)
postionIndicator(paginationActiveNumber)
})

And 3 other events for each number, 2 for when we are hovering or not and another one when clicking the different numbers of the pagination:

Array.from(paginationNumbers).forEach((element) => {
element.addEventListener('click', () => {
setActiveNumber(element)
postionIndicator(paginationActiveNumber)
})

element.addEventListener('mouseover', () => {postionIndicator(element)})

element.addEventListener('mouseout', () => {postionIndicator(paginationActiveNumber)})
})

And the last thing to do for the javascript part is to position the indicator when the pagination initializes for the first time:

postionIndicator(paginationActiveNumber)

and that's it, you have nice pagination with CSS and JS with fancy animations!

CSS Pagination design examples

In Frontend Planet we wrote an article of examples of different pagination styles for inspiration.

If you are interested, check out the article at this link.