Pagination

PohonGitHub
Displays data in paged format and provides navigation between pages.
<script setup lang="ts">
import { APaginationEllipsis, APaginationFirst, APaginationLast, APaginationList, APaginationListItem, APaginationNext, APaginationPrev, APaginationRoot } from 'akar';

const btnClasses = 'text-sm color-text font-500 p-1.5 rounded-md bg-background inline-flex gap-1.5 ring ring-ring-accented ring-inset transition-colors-280 items-center focus:outline-none active:bg-background-elevated aria-disabled:(bg-background opacity-75 cursor-not-allowed) disabled:(bg-background opacity-75 cursor-not-allowed) hover:bg-background-elevated focus-visible:(ring-2 ring-ring-inverted)';
</script>

<template>
  <APaginationRoot
    :total="100"
    :sibling-count="1"
    :items-per-page="10"
    show-edges
    :default-page="2"
  >
    <APaginationList
      v-slot="{ items }"
      class="flex gap-1 items-center"
    >
      <APaginationFirst :class="btnClasses">
        <i class="i-lucide:chevrons-left size-5" />
      </APaginationFirst>

      <APaginationPrev :class="btnClasses">
        <i class="i-lucide:chevron-left size-5" />
      </APaginationPrev>

      <template v-for="(page, index) in items">
        <APaginationListItem
          v-if="page.type === 'page'"
          :key="index"
          class="data-[selected]:bg-primary"
          :class="btnClasses"
          :value="page.value"
        >
          <span class="min-w-5">{{ page.value }}</span>
        </APaginationListItem>

        <APaginationEllipsis
          v-else
          :key="page.type"
          :index="index"
          :class="btnClasses"
        >
          <i class="i-lucide:ellipsis size-5" />
        </APaginationEllipsis>
      </template>
      <APaginationNext :class="btnClasses">
        <i class="i-lucide:chevron-right size-5" />
      </APaginationNext>
      <APaginationLast :class="btnClasses">
        <i class="i-lucide:chevrons-right size-5" />
      </APaginationLast>
    </APaginationList>
  </APaginationRoot>
</template>

Features

  • Enable quick access to first, or last page
  • Enable to show edges constantly, or not

Anatomy

Import all parts and piece them together.

<script setup>
import { APaginationEllipsis, APaginationFirst, APaginationLast, APaginationList, APaginationListItem, APaginationNext, APaginationPrev, APaginationRoot } from 'akar';
</script>

<template>
  <APaginationRoot>
    <APaginationList v-slot="{ items }">
      <APaginationFirst />
      <APaginationPrev />
      <template v-for="(page, index) in items">
        <APaginationListItem
          v-if="page.type === 'page'"
          :key="index"
        />
        <APaginationEllipsis
          v-else
          :key="page.type"
          :index="index"
        >
          &#8230;
        </APaginationEllipsis>
      </template>
      <APaginationNext />
      <APaginationLast />
    </APaginationList>
  </APaginationRoot>
</template>

Pohon

One benefit of using Akar is its flexibility and low-level control over the components. However, this also means that you may need to manually construct more complex UI elements by combining multiple Akar components together.

If you feel there's a lot of elements that needs to be constructed manually using Akar, consider using Pohon UI instead. It provides a higher-level abstraction over Akar components with pre-defined styles and behaviors that can help you build UIs faster.

API Reference

Root

Contains all of the paginations parts.

Props

Prop Default Type
as'nav'APrimitiveAsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChildboolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

defaultPage1number

The value of the page that should be active when initially rendered.

Use when you do not need to control the value state.

disabledboolean

When true, prevents the user from interacting with item

itemsPerPage*number

Number of items per page

pagenumber
showEdgesfalseboolean

When true, always show first page, last page, and ellipsis

siblingCount2number

Number of sibling should be shown around the current page

total0number

Number of items in your list

Emits

Event Type
update:page[value: number]

Event handler called when the page value changes

Slots

Slot Type
pagenumber

The controlled value of the current page. Can be binded as v-model:page.

pageCountnumber

Number of pages

List

Used to show the list of pages. It also makes pagination accessible to assistive technologies.

Props

Prop Default Type
as'div'APrimitiveAsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChildboolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

Slots

Slot Type
items{ type: 'ellipsis'; } | { type: 'page'; value: number; }

Pages item

Item

Used to render the button that changes the current page.

Data Attributes

Attribute Value
[data-selected]'true' | ''
[data-type]'page'

Ellipsis

Placeholder element when the list is long, and only a small amount of siblingCount was set and showEdges was set to true.

Props

Prop Default Type
as'div'APrimitiveAsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChildboolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

Data Attributes

Attribute Value
[data-type]'ellipsis'

First

Triggers that set the page value to 1

Props

Prop Default Type
as'button'APrimitiveAsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChildboolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

Prev

Triggers that set the page value to the previous page

Props

Prop Default Type
as'button'APrimitiveAsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChildboolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

Next

Triggers that set the page value to the next page

Props

Prop Default Type
as'button'APrimitiveAsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChildboolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

Last

Triggers that set the page value to the last page

Props

Prop Default Type
as'button'APrimitiveAsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChildboolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

Examples

With ellipsis

You can add APaginationEllipsis as a visual cue for more previous and after items.

<script setup lang="ts">
import { APaginationEllipsis, APaginationList, APaginationListItem, APaginationRoot } from 'akar';
</script>

<template>
  <APaginationRoot>
    <APaginationList v-slot="{ items }">
      <template v-for="(page, index) in items">
        <APaginationListItem
          v-if="page.type === 'page'"
          :key="index"
        />
        <APaginationEllipsis
          v-else
          :key="page.type"
          :index="index"
        >
          &#8230;
        </APaginationEllipsis>
      </template>
    </APaginationList>
  </APaginationRoot>
</template>

With first/last button

You can add APaginationFirst to allow user to navigate to first page, or APaginationLast to navigate to last page.

<script setup lang="ts">
import { APaginationFirst, APaginationLast, APaginationList, APaginationListItem, APaginationRoot } from 'akar';
</script>

<template>
  <APaginationRoot>
    <APaginationList>
      <APaginationFirst />
      ...
      <APaginationLast />
    </APaginationList>
  </APaginationRoot>
</template>

Control page programmatically

You can control the current page by passing it a reactive value.

<script setup lang="ts">
import { APaginationRoot } from 'akar';
import { ref } from 'vue';
import { Select } from './custom-select';

const currentPage = ref(1);
</script>

<template>
  <Select v-model="currentPage" />
  <APaginationRoot v-model:page="currentPage">
    ...
  </APaginationRoot>
</template>

Keyboard Interactions

Key Description
Tab

Moves focus to the next focusable element.

Space

When focus is on a any trigger, trigger selected page or arrow navigation

Enter

When focus is on a any trigger, trigger selected page or arrow navigation