diff --git a/src/components/index.ts b/src/components/index.ts
index 698b9596..70128252 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -33,3 +33,4 @@ export * from "./toggle";
export * from "./button-icon";
export * from "./copy-button";
export * from "./menu";
+export * from "./pagination";
diff --git a/src/components/pagination/Pagination.stories.mdx b/src/components/pagination/Pagination.stories.mdx
new file mode 100644
index 00000000..e3853775
--- /dev/null
+++ b/src/components/pagination/Pagination.stories.mdx
@@ -0,0 +1,56 @@
+import { Canvas, Meta, Story, ArgsTable, Source } from "@storybook/blocks";
+import { Pagination } from "./Pagination";
+import { useState } from "react";
+import { BUTTON_SIZE } from "../button/types";
+
+
+
+export const Template = ({ ...args }) => {
+ const [page, setPage] = useState(args.currentPage);
+ return (
+ {
+ setPage(p);
+ }}
+ />
+ );
+};
+
+# Pagination
+
+
+
+
+
+### Usage:
+
+To use, import the component `Pagination` from `@nilfoundation/ui-kit`.
+
+
+ `}
+/>
diff --git a/src/components/pagination/Pagination.tsx b/src/components/pagination/Pagination.tsx
new file mode 100644
index 00000000..c822a435
--- /dev/null
+++ b/src/components/pagination/Pagination.tsx
@@ -0,0 +1,142 @@
+import { useMemo } from "react";
+import { BUTTON_KIND, BUTTON_SIZE, Button, ButtonProps } from "../button";
+import { ChevronLeftIcon, ChevronRightIcon } from "../icons";
+import { PageElementProps, PaginationProps } from "./types";
+import { useStyletron } from "baseui";
+
+export const PageElement = ({
+ page,
+ linkMapper,
+ pageHandler,
+ label,
+ disabled,
+ active,
+ buttonSize,
+}: PageElementProps) => {
+ const buttonProps: ButtonProps = {
+ disabled,
+ kind: active ? BUTTON_KIND.primary : BUTTON_KIND.secondary,
+ size: buttonSize,
+ };
+ if (pageHandler) {
+ buttonProps.onClick = (e) => {
+ e.preventDefault();
+ pageHandler(page);
+ };
+ }
+ if (linkMapper && !disabled) {
+ return (
+
+ {
+ e.preventDefault();
+ if (pageHandler) pageHandler(page);
+ }}
+ aria-label={`${active ? "Current Page, " : ""}Page ${page}`}
+ aria-current={active}
+ >
+
+
+
+ );
+ }
+ return (
+
+ );
+};
+
+export const Pagination = ({
+ currentPage,
+ totalPages,
+ visiblePages = 3,
+ pageHandler,
+ linkMapper,
+ buttonSize = BUTTON_SIZE.default,
+}: PaginationProps) => {
+ const [css] = useStyletron();
+
+ const pages = useMemo(() => {
+ const pages = [1];
+ for (
+ let i = Math.max(currentPage - visiblePages, 2);
+ i <= Math.min(totalPages - 1, currentPage + visiblePages);
+ i++
+ ) {
+ pages.push(i);
+ }
+ pages.push(totalPages);
+ return pages;
+ }, [currentPage, totalPages, visiblePages]);
+
+ const elements = useMemo(() => {
+ const elements = [];
+ let prevPage = 1;
+ for (const page of pages) {
+ if (page - prevPage > 1) {
+ elements.push(
+
+ );
+ }
+ elements.push(
+
+
+
+ );
+ prevPage = page;
+ }
+ return elements;
+ }, [pages, pageHandler, linkMapper, currentPage, buttonSize]);
+
+ return (
+
+ );
+};
diff --git a/src/components/pagination/index.ts b/src/components/pagination/index.ts
new file mode 100644
index 00000000..36ecc098
--- /dev/null
+++ b/src/components/pagination/index.ts
@@ -0,0 +1,2 @@
+export * from "./Pagination";
+export * from "./types";
diff --git a/src/components/pagination/types.ts b/src/components/pagination/types.ts
new file mode 100644
index 00000000..164284b8
--- /dev/null
+++ b/src/components/pagination/types.ts
@@ -0,0 +1,21 @@
+import { ReactNode } from "react";
+import { BUTTON_SIZE } from "../button";
+
+export type PaginationProps = {
+ currentPage: number;
+ totalPages: number;
+ visiblePages?: number;
+ linkMapper?: (page: number) => string;
+ pageHandler?: (page: number) => void;
+ buttonSize?: BUTTON_SIZE;
+};
+
+export type PageElementProps = {
+ page: number;
+ label?: ReactNode;
+ linkMapper?: (page: number) => string;
+ pageHandler?: (page: number) => void;
+ disabled?: boolean;
+ active?: boolean;
+ buttonSize: BUTTON_SIZE;
+};