Skip to content
Gx
GitHub

Pagination

Links between pages of a result set.

<pagination.Pagination>
  <pagination.PaginationContent>
    <pagination.PaginationItem><pagination.PaginationPrevious href={gx.URL("/?page=1")} /></pagination.PaginationItem>
    <pagination.PaginationItem>
      <pagination.PaginationLink href={gx.URL("/?page=1")} active>1</pagination.PaginationLink>
    </pagination.PaginationItem>
    <pagination.PaginationItem>
      <pagination.PaginationLink href={gx.URL("/?page=2")}>2</pagination.PaginationLink>
    </pagination.PaginationItem>
    <pagination.PaginationItem><pagination.PaginationEllipsis /></pagination.PaginationItem>
    <pagination.PaginationItem><pagination.PaginationNext href={gx.URL("/?page=2")} /></pagination.PaginationItem>
  </pagination.PaginationContent>
</pagination.Pagination>

Installation

Run the command in the app module.

Terminal
gx add pagination

The command also installs button and icons.

The command writes these files.

File Path in the app
Pagination.gx ui/pagination/Pagination.gx
PaginationContent.gx ui/pagination/PaginationContent.gx
PaginationItem.gx ui/pagination/PaginationItem.gx
PaginationLink.gx ui/pagination/PaginationLink.gx
PaginationPrevious.gx ui/pagination/PaginationPrevious.gx
PaginationNext.gx ui/pagination/PaginationNext.gx
PaginationEllipsis.gx ui/pagination/PaginationEllipsis.gx
Pagination.fixtures.go ui/pagination/Pagination.fixtures.go
styles.go ui/pagination/styles.go
PaginationContent.fixtures.go ui/pagination/PaginationContent.fixtures.go
PaginationEllipsis.fixtures.go ui/pagination/PaginationEllipsis.fixtures.go
PaginationItem.fixtures.go ui/pagination/PaginationItem.fixtures.go
PaginationLink.fixtures.go ui/pagination/PaginationLink.fixtures.go
PaginationNext.fixtures.go ui/pagination/PaginationNext.fixtures.go
PaginationPrevious.fixtures.go ui/pagination/PaginationPrevious.fixtures.go

Install button and icons first.

Copy each file to its path in the app. Change each import of a registry package to the path of that package in the app.

ui/pagination/Pagination.gx
package pagination

props {
  // Class adds classes to the root element.
  Class    string = ""
  // Children is the content of the navigation: a PaginationContent.
  Children gx.Node
  // Attrs adds HTML attributes to the root element.
  Attrs    gx.Attrs = nil
}

<nav role="navigation" aria-label="pagination" data-slot="pagination" class={gx.Cx("mx-auto flex w-full justify-center", p.Class)} {...p.Attrs}>{p.Children}</nav>
ui/pagination/PaginationContent.gx
package pagination

props {
  // Class adds classes to the root element.
  Class    string = ""
  // Children is the pagination items.
  Children gx.Node
  // Attrs adds HTML attributes to the root element.
  Attrs    gx.Attrs = nil
}

<ul data-slot="pagination-content" class={gx.Cx("flex flex-row items-center gap-1", p.Class)} {...p.Attrs}>{p.Children}</ul>
ui/pagination/PaginationItem.gx
package pagination

props {
  // Class adds classes to the root element.
  Class    string = ""
  // Children is the content of the item: a link or an ellipsis.
  Children gx.Node
  // Attrs adds HTML attributes to the root element.
  Attrs    gx.Attrs = nil
}

<li data-slot="pagination-item" class={p.Class} {...p.Attrs}>{p.Children}</li>
ui/pagination/PaginationLink.gx
package pagination

import "github.com/alternayte/gx/registry/button"

props {
  // Href is the URL of the page.
  Href     gx.URL
  // Active marks the link of the current page. It sets aria-current and the outline style.
  Active   bool = false
  // Size sets the height and padding with a button size. The default is button.Icon, a square
  // link.
  Size     button.Size = button.Icon
  // Class adds classes to the root element.
  Class    string = ""
  // Children is the link label, for example the page number.
  Children gx.Node
  // Attrs adds HTML attributes to the root element.
  Attrs    gx.Attrs = nil
}

<a href={p.Href} data-slot="pagination-link" class={p.class()} {...p.attrs()}>{p.Children}</a>
ui/pagination/PaginationPrevious.gx
package pagination

import "github.com/alternayte/gx/registry/button"
import "github.com/alternayte/gx/registry/icons"

props {
  // Href is the URL of the previous page.
  Href  gx.URL
  // Class adds classes to the root element.
  Class string = ""
  // Attrs adds HTML attributes to the root element.
  Attrs gx.Attrs = nil
}

<PaginationLink href={p.Href} size={button.Md} class={gx.Cx("gap-1 px-2.5 sm:pl-2.5", p.Class)} attrs={p.attrs()}>
  <icons.ChevronLeft />
  <span class="hidden sm:block">Previous</span>
</PaginationLink>
ui/pagination/PaginationNext.gx
package pagination

import "github.com/alternayte/gx/registry/button"
import "github.com/alternayte/gx/registry/icons"

props {
  // Href is the URL of the next page.
  Href  gx.URL
  // Class adds classes to the root element.
  Class string = ""
  // Attrs adds HTML attributes to the root element.
  Attrs gx.Attrs = nil
}

<PaginationLink href={p.Href} size={button.Md} class={gx.Cx("gap-1 px-2.5 sm:pr-2.5", p.Class)} attrs={p.attrs()}>
  <span class="hidden sm:block">Next</span>
  <icons.ChevronRight />
</PaginationLink>
ui/pagination/PaginationEllipsis.gx
package pagination

import "github.com/alternayte/gx/registry/icons"

props {
  // Class adds classes to the root element.
  Class string = ""
  // Attrs adds HTML attributes to the root element.
  Attrs gx.Attrs = nil
}

<span aria-hidden="true" data-slot="pagination-ellipsis" class={gx.Cx("flex size-9 items-center justify-center", p.Class)} {...p.Attrs}>
  <icons.Ellipsis class="size-4" />
  <span class="sr-only">More pages</span>
</span>
ui/pagination/Pagination.fixtures.go
package pagination

import "github.com/alternayte/gx"

var PaginationFixtures = gx.Fixtures[PaginationProps]{
	"Trail": {Children: PaginationContent(PaginationContentProps{Children: gx.Frag(
		PaginationItem(PaginationItemProps{Children: PaginationPrevious(PaginationPreviousProps{Href: gx.URL("/?page=1")})}),
		PaginationItem(PaginationItemProps{Children: PaginationLink(PaginationLinkProps{Href: gx.URL("/?page=1"), Active: true, Children: gx.Text("1")})}),
		PaginationItem(PaginationItemProps{Children: PaginationLink(PaginationLinkProps{Href: gx.URL("/?page=2"), Children: gx.Text("2")})}),
		PaginationItem(PaginationItemProps{Children: PaginationEllipsis(PaginationEllipsisProps{})}),
		PaginationItem(PaginationItemProps{Children: PaginationNext(PaginationNextProps{Href: gx.URL("/?page=2")})}),
	)})},
}
ui/pagination/styles.go
package pagination

import (
	"github.com/alternayte/gx"
	"github.com/alternayte/gx/registry/button"
)

// class returns the classes of one pagination link: the outline button for
// the current page, the ghost button for the others. A zero size is Icon.
func (p PaginationLinkProps) class() string {
	size := p.Size
	if size == "" {
		size = button.Icon
	}
	if p.Active {
		return button.Class(button.Outline, size, p.Class)
	}
	return button.Class(button.Ghost, size, p.Class)
}

// attrs returns the state attributes of one link, then the caller's.
func (p PaginationLinkProps) attrs() gx.Attrs {
	if !p.Active {
		return p.Attrs
	}
	return append(gx.Attrs{{Key: "aria-current", Value: "page"}}, p.Attrs...)
}

// attrs returns the link attributes of the previous link.
func (p PaginationPreviousProps) attrs() gx.Attrs {
	return append(gx.Attrs{{Key: "aria-label", Value: "Go to previous page"}}, p.Attrs...)
}

// attrs returns the link attributes of the next link.
func (p PaginationNextProps) attrs() gx.Attrs {
	return append(gx.Attrs{{Key: "aria-label", Value: "Go to next page"}}, p.Attrs...)
}
ui/pagination/PaginationContent.fixtures.go
package pagination

import "github.com/alternayte/gx"

var PaginationContentFixtures = gx.Fixtures[PaginationContentProps]{"Empty": {}}
ui/pagination/PaginationEllipsis.fixtures.go
package pagination

import "github.com/alternayte/gx"

var PaginationEllipsisFixtures = gx.Fixtures[PaginationEllipsisProps]{"Default": {}}
ui/pagination/PaginationItem.fixtures.go
package pagination

import "github.com/alternayte/gx"

var PaginationItemFixtures = gx.Fixtures[PaginationItemProps]{"Empty": {}}

// PaginationItemWrap renders the item inside a list, as a page uses it.
func PaginationItemWrap(n gx.Node) gx.Node {
	return PaginationContent(PaginationContentProps{Children: n})
}
ui/pagination/PaginationLink.fixtures.go
package pagination

import "github.com/alternayte/gx"

var PaginationLinkFixtures = gx.Fixtures[PaginationLinkProps]{
	"Inactive": {Href: gx.URL("/?page=2"), Children: gx.Text("2")},
	"Active":   {Href: gx.URL("/?page=1"), Active: true, Children: gx.Text("1")},
}
ui/pagination/PaginationNext.fixtures.go
package pagination

import "github.com/alternayte/gx"

var PaginationNextFixtures = gx.Fixtures[PaginationNextProps]{"Default": {Href: gx.URL("/?page=2")}}
ui/pagination/PaginationPrevious.fixtures.go
package pagination

import "github.com/alternayte/gx"

var PaginationPreviousFixtures = gx.Fixtures[PaginationPreviousProps]{"Default": {Href: gx.URL("/?page=1")}}

The theme must define these tokens: --border, --accent, --accent-foreground, --ring.

Usage

<pagination.Pagination>
  <pagination.PaginationContent>
    <pagination.PaginationItem>
      <pagination.PaginationPrevious href={products.List{Page: p.Page - 1}} />
    </pagination.PaginationItem>
    <pagination.PaginationItem>
      <pagination.PaginationLink href={products.List{Page: 1}} active={p.Page == 1}>1</pagination.PaginationLink>
    </pagination.PaginationItem>
    <pagination.PaginationItem>
      <pagination.PaginationNext href={products.List{Page: p.Page + 1}} />
    </pagination.PaginationItem>
  </pagination.PaginationContent>
</pagination.Pagination>

A link has the look of a ghost button. The current page has the look of an outline button. PaginationPrevious and PaginationNext show a chevron. They hide their text on a narrow screen. PaginationLink takes a button.Size. The default is button.Icon.

Examples

Pagination: Trail

<pagination.Pagination>
  <pagination.PaginationContent>
    <pagination.PaginationItem><pagination.PaginationPrevious href={gx.URL("/?page=1")} /></pagination.PaginationItem>
    <pagination.PaginationItem>
      <pagination.PaginationLink href={gx.URL("/?page=1")} active>1</pagination.PaginationLink>
    </pagination.PaginationItem>
    <pagination.PaginationItem>
      <pagination.PaginationLink href={gx.URL("/?page=2")}>2</pagination.PaginationLink>
    </pagination.PaginationItem>
    <pagination.PaginationItem><pagination.PaginationEllipsis /></pagination.PaginationItem>
    <pagination.PaginationItem><pagination.PaginationNext href={gx.URL("/?page=2")} /></pagination.PaginationItem>
  </pagination.PaginationContent>
</pagination.Pagination>

PaginationContent: Empty

<pagination.PaginationContent children={gx.Frag()} />

PaginationEllipsis: Default

<pagination.PaginationEllipsis />

PaginationItem: Empty

<pagination.PaginationItem children={gx.Frag()} />
<pagination.PaginationLink href={gx.URL("/?page=2")}>2</pagination.PaginationLink>
<pagination.PaginationLink href={gx.URL("/?page=1")} active>1</pagination.PaginationLink>

PaginationNext: Default

<pagination.PaginationNext href={gx.URL("/?page=2")} />

PaginationPrevious: Default

<pagination.PaginationPrevious href={gx.URL("/?page=1")} />

API reference

A tag sets a prop by its name with a lower-case first letter: Class is class.

pagination.Pagination

Prop Type Default Description
Class string "" Class adds classes to the root element.
Children gx.Node Required Children is the content of the navigation: a PaginationContent.
Attrs gx.Attrs nil Attrs adds HTML attributes to the root element.

pagination.PaginationContent

Prop Type Default Description
Class string "" Class adds classes to the root element.
Children gx.Node Required Children is the pagination items.
Attrs gx.Attrs nil Attrs adds HTML attributes to the root element.

pagination.PaginationEllipsis

Prop Type Default Description
Class string "" Class adds classes to the root element.
Attrs gx.Attrs nil Attrs adds HTML attributes to the root element.

pagination.PaginationItem

Prop Type Default Description
Class string "" Class adds classes to the root element.
Children gx.Node Required Children is the content of the item: a link or an ellipsis.
Attrs gx.Attrs nil Attrs adds HTML attributes to the root element.
Prop Type Default Description
Href gx.URL Required Href is the URL of the page.
Active bool false Active marks the link of the current page. It sets aria-current and the outline style.
Size button.Size button.Icon Size sets the height and padding with a button size. The default is button.Icon, a square link.
Class string "" Class adds classes to the root element.
Children gx.Node Required Children is the link label, for example the page number.
Attrs gx.Attrs nil Attrs adds HTML attributes to the root element.

pagination.PaginationNext

Prop Type Default Description
Href gx.URL Required Href is the URL of the next page.
Class string "" Class adds classes to the root element.
Attrs gx.Attrs nil Attrs adds HTML attributes to the root element.

pagination.PaginationPrevious

Prop Type Default Description
Href gx.URL Required Href is the URL of the previous page.
Class string "" Class adds classes to the root element.
Attrs gx.Attrs nil Attrs adds HTML attributes to the root element.

Do and do not

Do

  • Pass typed route values to Href.
  • Set Active on the current page link.

Don't

  • Do not use a pagination link for an action.
  • Do not show more links than fit on one line.

Keyboard

Key Action
Tab Moves between the links.
Enter Follows the link.