diff --git a/README.md b/README.md
index c10b192e3..1a7ac9363 100644
--- a/README.md
+++ b/README.md
@@ -67,6 +67,7 @@ The accessibility column indicates whether the functionality is accessible in it
| [tooltip](https://lion-web-components.netlify.app/?path=/docs/overlays-tooltip--main) | [](https://www.npmjs.com/package/@lion/tooltip) | Tooltip element | [#175][i175] |
| **-- [Navigation System](https://lion-web-components.netlify.app/?path=/docs/navigation-intro--page) --** | | Components which are used to guide users | |
| [accordion](https://lion-web-components.netlify.app/?path=/docs/navigation-accordion--main) | [](https://www.npmjs.com/package/@lion/accordion) | Accordion | ✔️ |
+| [pagination](https://lion-web-components.netlify.app/?path=/docs/navigation-pagination--main) | [](https://www.npmjs.com/package/@lion/pagination) | Pagination | ✔️ |
| [steps](https://lion-web-components.netlify.app/?path=/docs/navigation-steps--main) | [](https://www.npmjs.com/package/@lion/steps) | Multi Step System | n/a |
| [tabs](https://lion-web-components.netlify.app/?path=/docs/navigation-tabs--main) | [](https://www.npmjs.com/package/@lion/tabs) | Move between a small number of equally important views | n/a |
| **-- [localize System](https://lion-web-components.netlify.app/?path=/docs/localize-intro--page) --** | | Localize text, numbers, dates and a way to store/fetch these data. | |
@@ -77,7 +78,7 @@ The accessibility column indicates whether the functionality is accessible in it
| [core](https://lion-web-components.netlify.app/?path=/docs/others-system-core--page) | [](https://www.npmjs.com/package/@lion/core) | Core System (exports LitElement, lit-html) | n/a |
| [ajax](https://lion-web-components.netlify.app/?path=/docs/others-ajax--performing-get-requests) | [](https://www.npmjs.com/package/@lion/ajax) | Fetching data via ajax request | n/a |
| [calendar](https://lion-web-components.netlify.app/?path=/docs/others-calendar--main) | [](https://www.npmjs.com/package/@lion/calendar) | Standalone calendar | [#195][i195], [#194][i194] |
-| [collapsible](https://lion-web-components.netlify.app/?path=/docs/others-collapsible--main) | [](https://www.npmjs.com/package/@lion/collapsible) | Combination of a button and a chunk of extra content | |
+| [collapsible](https://lion-web-components.netlify.app/?path=/docs/others-collapsible--main) | [](https://www.npmjs.com/package/@lion/collapsible) | Combination of a button and a chunk of extra content | ✔️ |
| **-- [Helpers](https://lion-web-components.netlify.app/?path=/docs/helpers-intro--page) --** | [](https://www.npmjs.com/package/@lion/helpers) | Helpers to make your and your life easier | |
| [sb-action-logger](https://lion-web-components.netlify.app/?path=/docs/helpers-storybook-action-logger--main) | | Storybook action logger |
diff --git a/docs/intros/intros-navigation.md b/docs/intros/intros-navigation.md
index c221c9576..d2e9d8acb 100644
--- a/docs/intros/intros-navigation.md
+++ b/docs/intros/intros-navigation.md
@@ -8,10 +8,12 @@ Navigational elements are used to guide users within your page.
## Packages
-| Package | Version | Description |
-| ---------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
-| [steps](?path=/docs/navigation-steps--default-story) | [](https://www.npmjs.com/package/@lion/steps) | Multi Step System |
-| [tabs](?path=/docs/navigation-tabs--default-story) | [](https://www.npmjs.com/package/@lion/tabs) | Move between a small number of equally important views |
+| Package | Version | Description |
+| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------- |
+| [accordion](?path=/docs/accordion-steps--default-story) | [](https://www.npmjs.com/package/@lion/accordion) | A component to toggle the display of sections of content |
+| [pagination](?path=/docs/pagination-steps--default-story) | [](https://www.npmjs.com/package/@lion/pagination) | A component that handles pagination |
+| [steps](?path=/docs/navigation-steps--default-story) | [](https://www.npmjs.com/package/@lion/steps) | Multi Step System |
+| [tabs](?path=/docs/navigation-tabs--default-story) | [](https://www.npmjs.com/package/@lion/tabs) | Move between a small number of equally important views |
```js script
export default {
diff --git a/packages/pagination/CHANGELOG.md b/packages/pagination/CHANGELOG.md
new file mode 100644
index 000000000..420e6f23d
--- /dev/null
+++ b/packages/pagination/CHANGELOG.md
@@ -0,0 +1 @@
+# Change Log
diff --git a/packages/pagination/README.md b/packages/pagination/README.md
new file mode 100644
index 000000000..46bd9b61e
--- /dev/null
+++ b/packages/pagination/README.md
@@ -0,0 +1,145 @@
+# Pagination
+
+`lion-pagination` component that handles pagination.
+
+```js script
+import { html } from 'lit-html';
+
+import './lion-pagination.js';
+
+export default {
+ title: 'Navigation/Pagination',
+};
+```
+
+```js preview-story
+export const main = () => html` `;
+```
+
+## Features
+
+- You can pass the total number of pages in the `count` parameter, and the current page in the `current` parameter. If `current` is not defined it will default to the value 1.
+- On a click or parameter change of `current` it will fire an event back called `current-changed`.
+
+## How to use
+
+### Installation
+
+```bash
+npm i --save @lion/pagination
+```
+
+```js
+import { LionPagination } from '@lion/pagination';
+// or
+import '@lion/pagination/lion-pagination.js';
+```
+
+### Usage
+
+```html
+
+```
+
+### Examples
+
+### Without current defined
+
+```js preview-story
+export const withoutCurrentPage = () => {
+ return html` `;
+};
+```
+
+### Ensure a count value
+
+Be sure to set a count value or you will get an "empty" pagination.
+
+```js preview-story
+export const ensureCount = () => {
+ return html` `;
+};
+```
+
+#### Methods
+
+There are the following methods available to control the pagination.
+
+- `next()`: move forward in pagination
+- `previous()`: goes back to pagination
+- `first()`: to the first page
+- `last()`: to the last page
+- `goto(pageNumber)`: to the specific page
+
+```js preview-story
+export const methods = () => {
+ setTimeout(() => {
+ document.getElementById('pagination-method-demo').innerText = document.getElementById(
+ 'pagination-method',
+ ).current;
+ });
+
+ return html`
+
The current page is:
+ {
+ const paginationState = document.getElementById('pagination-method-demo');
+ paginationState.innerText = e.target.current;
+ }}
+ >
+
+
+
+
+
+
+
+
+
+
+
+ `;
+};
+```
+
+#### Event
+
+`lion-pagination` fires an event on button click to notify the component's current state. It is useful for analytics purposes or to perform some actions on page change.
+
+- `@current-changed`: triggers when the current page is changed
+
+```js preview-story
+export const event = () => {
+ setTimeout(() => {
+ document.getElementById('pagination-event-demo-text').innerText = document.getElementById(
+ 'pagination-event-demo',
+ ).current;
+ });
+
+ return html`
+
The current page is:
+ {
+ const paginationState = document.getElementById('pagination-event-demo-text');
+ paginationState.innerText = e.target.current;
+ }}
+ >
+ `;
+};
+```
diff --git a/packages/pagination/index.js b/packages/pagination/index.js
new file mode 100644
index 000000000..279660b2b
--- /dev/null
+++ b/packages/pagination/index.js
@@ -0,0 +1 @@
+export { LionPagination } from './src/LionPagination.js';
diff --git a/packages/pagination/lion-pagination.js b/packages/pagination/lion-pagination.js
new file mode 100644
index 000000000..bad17b764
--- /dev/null
+++ b/packages/pagination/lion-pagination.js
@@ -0,0 +1,3 @@
+import { LionPagination } from './src/LionPagination.js';
+
+customElements.define('lion-pagination', LionPagination);
diff --git a/packages/pagination/package.json b/packages/pagination/package.json
new file mode 100644
index 000000000..bcf67f2bc
--- /dev/null
+++ b/packages/pagination/package.json
@@ -0,0 +1,46 @@
+{
+ "name": "@lion/pagination",
+ "version": "0.0.0",
+ "description": "A component that handles pagination.",
+ "license": "MIT",
+ "author": "ing-bank",
+ "homepage": "https://github.com/ing-bank/lion/",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/ing-bank/lion.git",
+ "directory": "packages/pagination"
+ },
+ "main": "index.js",
+ "module": "index.js",
+ "files": [
+ "*.d.ts",
+ "*.js",
+ "docs",
+ "src",
+ "test",
+ "test-helpers",
+ "translations",
+ "types"
+ ],
+ "scripts": {
+ "prepublishOnly": "../../scripts/npm-prepublish.js",
+ "start": "cd ../../ && yarn dev-server --open packages/pagination/README.md",
+ "test": "cd ../../ && yarn test:browser --grep \"packages/pagination/test/**/*.test.js\"",
+ "test:watch": "cd ../../ && yarn test:browser:watch --grep \"packages/pagination/test/**/*.test.js\""
+ },
+ "sideEffects": [
+ "lion-pagination.js"
+ ],
+ "dependencies": {
+ "@lion/core": "0.10.0",
+ "@lion/localize": "0.14.2"
+ },
+ "keywords": [
+ "lion",
+ "pagination",
+ "web-components"
+ ],
+ "publishConfig": {
+ "access": "public"
+ }
+}
diff --git a/packages/pagination/src/LionPagination.js b/packages/pagination/src/LionPagination.js
new file mode 100644
index 000000000..8afbaae00
--- /dev/null
+++ b/packages/pagination/src/LionPagination.js
@@ -0,0 +1,296 @@
+import { LitElement, html, css } from '@lion/core';
+import { LocalizeMixin } from '@lion/localize';
+/**
+ * `LionPagination` is a class for custom Pagination element (`` web component).
+ *
+ * @customElement lion-pagination
+ * @extends LitElement
+ */
+export class LionPagination extends LocalizeMixin(LitElement) {
+ static get styles() {
+ return css`
+ :host {
+ cursor: default;
+ }
+
+ ul {
+ list-style: none;
+ padding: 0;
+ text-align: center;
+ }
+
+ li {
+ display: inline-block;
+ }
+
+ button[aria-current='true'] {
+ font-weight: bold;
+ }
+ `;
+ }
+
+ static get localizeNamespaces() {
+ return [
+ {
+ 'lion-pagination': locale => {
+ switch (locale) {
+ case 'bg-BG':
+ return import('../translations/bg.js');
+ case 'cs-CZ':
+ return import('../translations/cs.js');
+ case 'de-AT':
+ case 'de-DE':
+ return import('../translations/de.js');
+ case 'en-AU':
+ case 'en-GB':
+ case 'en-PH':
+ case 'en-US':
+ return import('../translations/en.js');
+ case 'es-ES':
+ return import('../translations/es.js');
+ case 'fr-FR':
+ case 'fr-BE':
+ return import('../translations/fr.js');
+ case 'hu-HU':
+ return import('../translations/hu.js');
+ case 'it-IT':
+ return import('../translations/it.js');
+ case 'nl-BE':
+ case 'nl-NL':
+ return import('../translations/nl.js');
+ case 'pl-PL':
+ return import('../translations/pl.js');
+ case 'ro-RO':
+ return import('../translations/ro.js');
+ case 'ru-RU':
+ return import('../translations/ru.js');
+ case 'sk-SK':
+ return import('../translations/sk.js');
+ case 'uk-UA':
+ return import('../translations/uk.js');
+ case 'zh-CN':
+ return import('../translations/zh.js');
+ default:
+ return import('../translations/en.js');
+ }
+ },
+ },
+ ...super.localizeNamespaces,
+ ];
+ }
+
+ static get properties() {
+ return {
+ current: {
+ type: Number,
+ reflect: true,
+ },
+ count: {
+ type: Number,
+ reflect: true,
+ },
+ };
+ }
+
+ set current(value) {
+ if (value !== this.current) {
+ const oldValue = this.current;
+ this.__current = value;
+ this.dispatchEvent(new Event('current-changed'));
+ this.requestUpdate('current', oldValue);
+ }
+ }
+
+ get current() {
+ return this.__current;
+ }
+
+ constructor() {
+ super();
+ this.__visiblePages = 5;
+ this.current = 1;
+ this.count = 0;
+ }
+
+ /**
+ * Go next in pagination
+ * @public
+ */
+ next() {
+ if (this.current < this.count) {
+ this.__fire(this.current + 1);
+ }
+ }
+
+ /**
+ * Go to first page
+ * @public
+ */
+ first() {
+ if (this.count >= 1) {
+ this.__fire(1);
+ }
+ }
+
+ /**
+ * Go to the last page
+ * @public
+ */
+ last() {
+ if (this.count >= 1) {
+ this.__fire(this.count);
+ }
+ }
+
+ /**
+ * Go to the specific page
+ * @public
+ */
+ goto(pageNumber) {
+ if (pageNumber >= 1 && pageNumber <= this.count) {
+ this.__fire(pageNumber);
+ }
+ }
+
+ /**
+ * Go back in pagination
+ * @public
+ */
+ previous() {
+ if (this.current !== 1) {
+ this.__fire(this.current - 1);
+ }
+ }
+
+ /**
+ * Set desired page in the pagination and fire the current changed event.
+ * @param {Number} page page number to be set
+ * @private
+ */
+ __fire(page) {
+ if (page !== this.current) {
+ this.current = page;
+ }
+ }
+
+ /**
+ * Calculate nav list based on current page selection.
+ * @returns {Array}
+ * @private
+ */
+ __calculateNavList() {
+ const start = 1;
+ const finish = this.count;
+ // If there are more pages then we want to display we have to redo the list each time
+ // Else we can just return the same list every time.
+ if (this.count > this.__visiblePages) {
+ // Calculate left side of current page and right side
+ const pos3 = this.current - 1;
+ const pos4 = this.current;
+ const pos5 = this.current + 1;
+ // if pos 3 is lower than 4 we have a predefined list of elements
+ if (pos4 <= 4) {
+ const list = Array(this.__visiblePages)
+ .fill()
+ .map((_, idx) => start + idx);
+ list.push('...');
+ list.push(this.count);
+ return list;
+ }
+ // if we are close to the end of the list with the current page then we have again a predefined list
+ if (finish - pos4 <= 3) {
+ const list = [];
+ list.push(1);
+ list.push('...');
+ const listRemaining = Array(this.__visiblePages)
+ .fill()
+ .map((_, idx) => this.count - this.__visiblePages + 1 + idx);
+ return list.concat(listRemaining);
+ }
+
+ return [start, '...', pos3, pos4, pos5, '...', finish];
+ }
+ return Array(finish - start + 1)
+ .fill()
+ .map((_, idx) => start + idx);
+ }
+
+ /**
+ * Get previous or next button template.
+ * This method can be overridden to apply customized template in wrapper.
+ * @param {String} label namespace label i.e. next or previous
+ * @returns {TemplateResult} icon template
+ * @protected
+ */
+ // eslint-disable-next-line class-methods-use-this
+ _prevNextIconTemplate(label) {
+ return label === 'next' ? html` > ` : html` < `;
+ }
+
+ /**
+ * Get next or previous button template.
+ * This method can be overridden to apply customized template in wrapper.
+ * @param {String} label namespace label i.e. next or previous
+ * @param {Number} pageNumber page number to be set
+ * @param {String} namespace namespace prefix for translations
+ * @returns {TemplateResult} nav item template
+ * @protected
+ */
+ _prevNextButtonTemplate(label, pageNumber, namespace = 'lion') {
+ return html`
+
+
+
+ `;
+ }
+
+ /**
+ * Get disabled button template.
+ * This method can be overridden to apply customized template in wrapper.
+ * @param {String} label namespace label i.e. next or previous
+ * @returns {TemplateResult} nav item template
+ * @protected
+ */
+ _disabledButtonTemplate(label) {
+ return html`
+