diff --git a/.changeset/fair-pants-grab.md b/.changeset/fair-pants-grab.md
new file mode 100644
index 00000000..c81b85ef
--- /dev/null
+++ b/.changeset/fair-pants-grab.md
@@ -0,0 +1,5 @@
+---
+'@saas-ui/react': minor
+---
+
+Added Pagination component
diff --git a/packages/saas-ui-react/src/components/icons/icons.tsx b/packages/saas-ui-react/src/components/icons/icons.tsx
index 97723f68..adbe5f39 100644
--- a/packages/saas-ui-react/src/components/icons/icons.tsx
+++ b/packages/saas-ui-react/src/components/icons/icons.tsx
@@ -117,3 +117,14 @@ export const CheckIcon = createIcon({
),
})
+
+export const EllipsisIcon = createIcon({
+ displayName: 'EllipsisIcon',
+ path: (
+
+
+
+
+
+ ),
+})
diff --git a/packages/saas-ui-react/src/components/pagination/index.ts b/packages/saas-ui-react/src/components/pagination/index.ts
new file mode 100644
index 00000000..f4693419
--- /dev/null
+++ b/packages/saas-ui-react/src/components/pagination/index.ts
@@ -0,0 +1 @@
+export * as Pagination from './pagination.tsx'
diff --git a/packages/saas-ui-react/src/components/pagination/pagination.tsx b/packages/saas-ui-react/src/components/pagination/pagination.tsx
new file mode 100644
index 00000000..c60e49f7
--- /dev/null
+++ b/packages/saas-ui-react/src/components/pagination/pagination.tsx
@@ -0,0 +1,162 @@
+'use client'
+
+import { forwardRef, useMemo } from 'react'
+
+import type { ButtonProps, TextProps } from '@chakra-ui/react'
+import {
+ Button,
+ Pagination as ChakraPagination,
+ IconButton,
+ Text,
+ createContext,
+ usePaginationContext,
+} from '@chakra-ui/react'
+
+import {
+ ChevronLeftIcon,
+ ChevronRightIcon,
+ EllipsisIcon,
+} from '#components/icons/icons.ts'
+
+interface ButtonVariantMap {
+ current: ButtonProps['variant']
+ default: ButtonProps['variant']
+ ellipsis: ButtonProps['variant']
+}
+
+type PaginationVariant = 'outline' | 'solid' | 'subtle'
+
+interface ButtonVariantContext {
+ size: ButtonProps['size']
+ variantMap: ButtonVariantMap
+}
+
+const [RootPropsProvider, useRootProps] = createContext({
+ name: 'RootPropsProvider',
+})
+
+export interface RootProps extends Omit {
+ size?: ButtonProps['size']
+ variant?: PaginationVariant
+}
+
+const variantMap: Record = {
+ outline: { default: 'ghost', ellipsis: 'plain', current: 'outline' },
+ solid: { default: 'outline', ellipsis: 'outline', current: 'solid' },
+ subtle: { default: 'ghost', ellipsis: 'plain', current: 'subtle' },
+}
+
+export const Root = forwardRef(
+ function PaginationRoot(props, ref) {
+ const { size = 'sm', variant = 'outline', ...rest } = props
+ return (
+
+
+
+ )
+ },
+)
+
+export const Ellipsis = forwardRef<
+ HTMLDivElement,
+ ChakraPagination.EllipsisProps
+>(function PaginationEllipsis(props, ref) {
+ const { size, variantMap } = useRootProps()
+ return (
+
+
+
+ )
+})
+
+export const Item = forwardRef(
+ function PaginationItem(props, ref) {
+ const { page } = usePaginationContext()
+ const { size, variantMap } = useRootProps()
+
+ const current = page === props.value
+ const variant = current ? variantMap.current : variantMap.default
+
+ return (
+
+
+
+ )
+ },
+)
+
+export const PrevButton = forwardRef<
+ HTMLButtonElement,
+ ChakraPagination.PrevTriggerProps
+>(function PaginationPrevTrigger(props, ref) {
+ const { size, variantMap } = useRootProps()
+
+ return (
+
+
+ {props.children ?? }
+
+
+ )
+})
+
+export const NextButton = forwardRef<
+ HTMLButtonElement,
+ ChakraPagination.NextTriggerProps
+>(function PaginationNextTrigger(props, ref) {
+ const { size, variantMap } = useRootProps()
+ const { nextPage } = usePaginationContext()
+
+ return (
+
+
+ {props.children ?? }
+
+
+ )
+})
+
+export const Items = (props: React.HTMLAttributes) => {
+ return (
+
+ {({ pages }) =>
+ pages.map((page, index) => {
+ return page.type === 'ellipsis' ? (
+
+ ) : (
+
+ )
+ })
+ }
+
+ )
+}
+
+interface PageTextProps extends TextProps {
+ format?: 'short' | 'compact' | 'long'
+}
+
+export const PageText = forwardRef(
+ function PaginationPageText(props, ref) {
+ const { format = 'compact', ...rest } = props
+ const { page, pages, pageRange, count } = usePaginationContext()
+ const content = useMemo(() => {
+ if (format === 'short') return `${page} / ${pages.length}`
+ if (format === 'compact') return `${page} of ${pages.length}`
+ return `${pageRange.start + 1} - ${pageRange.end} of ${count}`
+ }, [format, page, pages.length, pageRange, count])
+
+ return (
+
+ {content}
+
+ )
+ },
+)
+
+export const PrevTrigger = ChakraPagination.PrevTrigger
+export const NextTrigger = ChakraPagination.NextTrigger