Paginations
Overview
Pagination helps to chunk a massive data from server which can decrease your website performance.
JSXPine has two types of pagination: input and select. Discover what you can achieve below.
Installation
Notes
To use this component, you need to initialize your project first. If not done yet, run one of the following command:
npx jsxpine init or yarn jsxpine init or pnpm jsxpine init or bunx jsxpine init.
Go to the installation and usage page to learn more.
jsxpine add pagination
Copied !
-------------------- Components Dependencies -------------------------
import clsx from "clsx";
/**
* @typedef HTMLButtonTagWithChildren
* @type {import("@kitajs/html").PropsWithChildren<Omit<JSX.HtmlButtonTag, "className"> & import("../common/props").CLSXClassProps>}
*/
/**
* @typedef {Object} ButtonProps
* @type {{ text?: string } & HTMLButtonTagWithChildren & import("../common/props").BorderRadiusProps & import("../common/props").SizeProps & import("../common/props").VariantColorProps}
*/
/**
* Button component props
* @param {ButtonProps} props
*/
export function Button({
children,
class: className,
size = "md",
text,
variant = "solid",
borderRadius = "rounded",
...restProps
}) {
/**
* @type {Map<import("../common/types").VariantColorType, string>}
*/
const variantColorMap = new Map([
["solid", "btn"],
["outlined", "btn-outlined"],
["inversed", "btn-inversed"]
]);
/**
* @type {Map<import("../common/types").SizeType, string>}
*/
const sizeMap = new Map([
["xs", "text-xs px-2 py-1"],
["sm", "px-4 py-2 text-sm"],
["md", "px-4 py-2"],
["lg", "px-8 py-4 text-lg"],
["xl", "px-12 py-6 text-xl"],
["2xl", "px-16 py-8 text-4xl"]
]);
/**
* @type {Map<import("../common/types").BorderRadiusType, string>}
*/
const borderRadiusMap = new Map([
["square", "rounded-none"],
["rounded", "rounded"],
["arc", "rounded-xl"],
["pill", "rounded-full"],
["curve", "rounded-lg"],
["circle", "aspect-square rounded-full"]
]);
return (
<button
class={clsx(
variantColorMap.get(variant),
sizeMap.get(size),
borderRadiusMap.get(borderRadius),
className
)}
{...restProps}
>
{text ? <span safe>{text}</span> : children}
</button>
);
}
/**
* Primary Button component props
* @type {import("../common/props").JSXComponent<ButtonProps>}
*/
export function PrimaryButton(props) {
const { children, class: className, variant = "solid", ...restProps } = props;
/**
* @type {Map<import("../common/types").VariantColorType, string>}
*/
const variantClassMap = new Map([
["solid", "btn-primary"],
["outlined", "btn-primary-outlined"],
["inversed", "btn-primary-inversed"]
]);
return (
<Button
class={[variantClassMap.get(variant), className].join(" ")}
{...restProps}
>
{children}
</Button>
);
}
/**
* Secondary Button component props
* @type {import("../common/props").JSXComponent<ButtonProps>}
*/
export function SecondaryButton(props) {
const { children, class: className, variant = "solid", ...restProps } = props;
/**
* @type {Map<import("../common/types").VariantColorType, string>}
*/
const variantClassMap = new Map([
["solid", "btn-secondary"],
["outlined", "btn-secondary-outlined"],
["inversed", "btn-secondary-inversed"]
]);
return (
<Button
class={[variantClassMap.get(variant), className].join(" ")}
{...restProps}
>
{children}
</Button>
);
}
/**
* Success Button component props
* @type {import("../common/props").JSXComponent<ButtonProps>}
*/
export function SuccessButton(props) {
const { children, class: className, variant = "solid", ...restProps } = props;
/**
* @type {Map<import("../common/types").VariantColorType, string>}
*/
const variantClassMap = new Map([
["solid", "btn-success"],
["outlined", "btn-success-outlined"],
["inversed", "btn-success-inversed"]
]);
return (
<Button
class={[variantClassMap.get(variant), className].join(" ")}
{...restProps}
>
{children}
</Button>
);
}
/**
* Danger Button component props
* @type {import("../common/props").JSXComponent<ButtonProps>}
*/
export function DangerButton(props) {
const { children, class: className, variant = "solid", ...restProps } = props;
/**
* @type {Map<import("../common/types").VariantColorType, string>}
*/
const variantClassMap = new Map([
["solid", "btn-danger"],
["outlined", "btn-danger-outlined"],
["inversed", "btn-danger-inversed"]
]);
return (
<Button
class={[variantClassMap.get(variant), className].join(" ")}
{...restProps}
>
{children}
</Button>
);
}
/**
* Info Button component props
* @type {import("../common/props").JSXComponent<ButtonProps>}
*/
export function InfoButton(props) {
const { children, class: className, variant = "solid", ...restProps } = props;
/**
* @type {Map<import("../common/types").VariantColorType, string>}
*/
const variantClassMap = new Map([
["solid", "btn-info"],
["outlined", "btn-info-outlined"],
["inversed", "btn-info-inversed"]
]);
return (
<Button
class={[variantClassMap.get(variant), className].join(" ")}
{...restProps}
>
{children}
</Button>
);
}
/**
* Warning Button component props
* @type {import("../common/props").JSXComponent<ButtonProps>}
*/
export function WarningButton(props) {
const { children, class: className, variant = "solid", ...restProps } = props;
/**
* @type {Map<import("../common/types").VariantColorType, string>}
*/
const variantClassMap = new Map([
["solid", "btn-warning"],
["outlined", "btn-warning-outlined"],
["inversed", "btn-warning-inversed"]
]);
return (
<Button
class={[variantClassMap.get(variant), className].join(" ")}
{...restProps}
>
{children}
</Button>
);
}
import { icons } from "@iconify-json/ri/icons.json";
import clsx from "clsx";
import { SVG } from "./svg.component";
/**
* @typedef {`ri.${keyof typeof import("@iconify-json/ri/icons.json")["icons"]}`} IconName
*/
/**
* @typedef IconProps
* @type {{size?: number, name: IconName, color?: string, applyDefsId?: string} & import("./svg.component").SVGProps}
*/
/**
* Icon component props
* @param {Omit<IconProps, "viewBox">} props
*/
export function Icon({
children,
size = 4,
name,
applyDefsId,
class: className,
...restProps
}) {
const iconType = name.split(".")[0];
const iconName = /** @type {keyof typeof icons} */ (name.split(".")[1]);
if (!icons[iconName]) {
console.error(`"${name}" is not an icon from iconify/${iconType}`);
return "";
}
const { body } = icons[iconName];
// The purpose is to retrieve value from d attribute
let retrieveDValue = "";
const bodyMatch = body.match(/d=".+"/g);
const retrieveDAttribute = bodyMatch ? bodyMatch[0] : "";
if (retrieveDAttribute) {
retrieveDValue = retrieveDAttribute.slice(3, -2);
}
return (
<SVG
viewBox={"0 0 24 24"}
{...restProps}
class={clsx(`size-${size}`, className)}
>
{children}
<path
stroke-linecap="round"
stroke-linejoin="round"
fill={applyDefsId ? `url(#${applyDefsId})` : "currentColor"}
d={retrieveDValue}
/>
</SVG>
);
}
/**
* @typedef SVGProps
* @type {{fill?: string, stroke?: string, strokeWidth?: number, viewBox: string } & Omit<JSX.HtmlTag, "className"> & import("../common/props").CLSXClassProps}
*/
/**
* SVG component props
* @type {import("../common/props").JSXComponent<SVGProps>}
*/
export function SVG(props) {
const {
children,
class: className,
fill = "none",
stroke = "currentColor",
strokeWidth = 0.5,
...restProps
} = props;
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill={fill}
stroke={stroke}
class={className}
style={{ strokeWidth: String(strokeWidth) }}
{...restProps}
>
{children}
</svg>
)
}
import { Icon } from "./icon.component";
import clsx from "clsx";
/**
* @typedef {Object} InputProps
* @type {Omit<JSX.HtmlInputTag, "className"> & import("../common/props").CLSXClassProps}
*/
/**
* @typedef TextInputProps
* @type {InputProps}
*/
/**
* @typedef PasswordInputProps
* @type {{ hideIcon?: boolean } & InputProps}
*/
/**
* @typedef NumberInputProps
* @type {Omit<InputProps, "placeholder" | "min" | "max"> & { min?: number, max?: number }}
*/
/**
* @typedef TextareaInputProps
* @type {{ value?: string, noResize?: boolean} & Omit<JSX.HtmlTextAreaTag, "className"> & import("../common/props").CLSXClassProps}
*/
/**
* @typedef {Object} DefaultSelectOptionType
* @property {string} label
* @property {string | number} [value]
* @property {boolean} [disabled]
*/
/**
* @typedef SelectOptionType
* @type {DefaultSelectOptionType & Record<string, unknown>}
*/
/**
* @typedef SelectInputProps
* @type {{ value?: string | number | string[], placeholder?: string, items?: SelectOptionType[], hidePlaceholder?: boolean } & Omit<JSX.HtmlSelectTag, "className"> & import("../common/props").CLSXClassProps}
*/
/**
* @typedef CheckboxInputProps
* @type {Omit<InputProps, "placeholder">}
*/
/**
* @typedef RadioInputProps
* @type {Omit<InputProps, "placeholder">}
*/
/**
* Checkbox Input props
* @type {import("../common/props").JSXComponent<CheckboxInputProps>}
*/
export function CheckboxInput(props) {
return <input type="checkbox" {...props} />;
}
/**
* Date Input props
* @type {import("../common/props").JSXComponent<TextInputProps>}
*/
export function DateInput(props) {
const { value = "", class: className, ...restProps } = props;
return (
<div
class={clsx("input flex items-center justify-center gap-x-2", className)}
x-data={`{ value: "${value}" }`}
>
<input
x-ref="dateInput"
type="date"
{...restProps}
x-model="value"
class="flex-1 px-1"
/>
{/* Because calendar-picker-icon doesn't change with theme toggle */}
<button x-on:click="$refs.dateInput.showPicker()">
<Icon name="ri.calendar-line" />
</button>
</div>
);
}
/**
* Email Input props
* @type {import("../common/props").JSXComponent<TextInputProps>}
*/
export function EmailInput(props) {
const { value = "", class: className, ...restProps } = props;
return (
<div
class={clsx("input input-primary flex items-center gap-x-2", className)}
x-data={`{ value: "${value}" }`}
>
<input type="email" {...restProps} x-model="value" class="flex-1 px-1" />
<button
type="button"
x-bind:disabled="!value"
x-on:click="value = ''"
class="flex items-center justify-center"
x-bind:class="value ? 'opacity-100' : 'opacity-0'"
>
<Icon name="ri.close-line" size={5} />
</button>
</div>
);
}
/**
* File Input props
* @type {import("../common/props").JSXComponent<TextInputProps>}
*/
export function FileInput(props) {
const { value = "", class: className, ...restProps } = props;
return (
<div
class={clsx("input flex items-center justify-center", className)}
x-data={`{ value: "${value}" }`}
>
<input type="file" {...restProps} x-model="value" class="flex-1 px-1" />
</div>
);
}
/**
* Number Input props
* @type {import("../common/props").JSXComponent<NumberInputProps>}
*/
export function NumberInput(props) {
const { min = 1, max, value = 1, class: className, ...restProps } = props;
return (
<input
type="number"
x-data={`{ value: ${value} }`}
class={clsx("text-center input out-of-range:bg-danger-500", className)}
{...restProps}
min={String(min)}
max={String(max)}
x-model="value"
pattern="/\d/g"
/>
);
}
/**
* Password Input props
* @type {import("../common/props").JSXComponent<PasswordInputProps>}
*/
export function PasswordInput(props) {
const {
value = "",
hideIcon = false,
class: className,
...restProps
} = props;
return (
<div
class={clsx("input input-primary flex items-center gap-x-2", className)}
x-data={`{ value: "${value}", show: false }`}
>
<input
x-bind:type="show ? 'text' : 'password'"
{...restProps}
x-model="value"
class="flex-1 px-1"
/>
{!hideIcon ? (
<button
type="button"
x-bind:disabled="!value"
x-on:click="show = !show"
class="flex items-center justify-center"
>
<template x-if="!show">
<Icon name="ri.eye-line" stroke-width="0.5" size={5} />
</template>
<template x-if="show">
<Icon name="ri.eye-off-line" stroke-width="0.5" size={5} />
</template>
</button>
) : null}
</div>
);
}
/**
* Radio Input props
* @type {import("../common/props").JSXComponent<RadioInputProps>}
*/
export function RadioInput(props) {
return <input type="radio" {...props} />;
}
/**
* Select Input props
* @type {import("../common/props").JSXComponent<SelectInputProps>}
*/
export function SelectInput(props) {
const {
items = [],
placeholder = "Select a value",
hidePlaceholder = false,
value,
class: className,
...restProps
} = props;
return (
<select
{...restProps}
x-data={`{ value: "${value}" }`}
class={clsx(
"w-full p-2 text-md border border-base-light rounded cursor-pointer focus:outline-none focus:ring-2 focus:border-primary"
)}
>
<option class={clsx({ hidden: hidePlaceholder })} selected safe>
{placeholder}
</option>
{items.map((item) => {
return (
<option value={String(item.value)} safe>
{item.label}
</option>
);
})}
</select>
);
}
/**
* Text Input props
* @type {import("../common/props").JSXComponent<TextInputProps>}
*/
export function TextInput(props) {
const { value = "", class: className, ...restProps } = props;
return (
<div
class={clsx("input input-primary flex items-center gap-x-2", className)}
x-data={`{ value: "${value}" }`}
>
<input type="text" {...restProps} x-model="value" class="flex-1 px-1" />
<button
type="button"
x-bind:disabled="!value"
x-on:click="value = ''"
class="flex items-center justify-center"
x-bind:class="value ? 'opacity-100' : 'opacity-0'"
>
<Icon name="ri.close-line" size={5} />
</button>
</div>
);
}
/**
* Textarea Input props
* @type {import("../common/props").JSXComponent<TextareaInputProps>}
*/
export function TextareaInput(props) {
const {
value = "",
noResize = false,
class: className,
...restProps
} = props;
return (
<textarea
x-data={`{ value: "${value}" }`}
x-model="value"
class={clsx("border rounded-lg h-full p-2", className)}
{...restProps}
></textarea>
);
}
/**
* Text Input props
* @type {import("../common/props").JSXComponent<TextInputProps>}
*/
export function TimeInput(props) {
const { value = "", class: className, ...restProps } = props;
return (
<div
class={clsx("input flex items-center justify-center gap-x-2", className)}
x-data={`{ value: "${value}" }`}
>
<input
x-ref="timeInput"
type="time"
{...restProps}
x-model="value"
class="flex-1 px-1"
/>
{/* Because calendar-picker-icon doesn't change with theme toggle */}
<button x-on:click="$refs.timeInput.showPicker()">
<Icon name="ri.time-line" />
</button>
</div>
);
}
import { Icon } from "./icon.component";
import clsx from "clsx";
/**
* @typedef SelectProps
* @type {import("./input.component").SelectInputProps & { noInputIcon?: boolean, defaultValue?: import("./input.component").SelectOptionType | null }}
*/
/**
* Select component props
* @type {import("../common/props").JSXComponent<SelectProps>}
*/
export function Select(props) {
const {
items = [],
class: className,
placeholder = "Select Item",
noInputIcon = false,
disabled,
defaultValue,
...restProps
} = props;
return (
<div
x-data={`dropdownSelect(${JSON.stringify(items)}, ${defaultValue ? JSON.stringify(defaultValue) : "" })`}
x-on:keydown="selectKeydown($event);"
class={clsx("relative", className)}
{...{
...restProps,
"@keydown.escape": `
if (selectOpen){
selectOpen = false;
}
`,
"@keydown.down.prevent": `
if (selectOpen) {
selectableItemActiveNext();
} else {
selectOpen = true;
}
`,
"@keydown.up.prevent": `
if(selectOpen) {
selectableItemActivePrevious();
} else {
selectOpen=true;
}
`,
"x-on:keydown.enter": `
selectedItem = selectableItemActive;
selectOpen=false;
$dispatch('select', selectableItemActive);
`
}}
>
<button
x-ref="selectButton"
type="button"
x-on:click="selectOpen =! selectOpen"
x-bind:class="{ 'focus:ring-2 focus:ring-offset-2 focus:ring-base' : !selectOpen }"
class="relative w-full flex items-center justify-between p-1 gap-x-2 text-left hover:cursor-pointer disabled:cursor-not-allowed disabled:text-base/30 focus:outline-none text-sm"
disabled={disabled}
>
<span
x-text={`selectedItem ? selectedItem.label : "${placeholder}"`}
class="truncate text-center"
/>
{!noInputIcon && (
<span class="right-0 flex items-center pointer-events-none">
<Icon name="ri.expand-up-down-line" stroke-width="0.5" />
</span>
)}
</button>
<ul
x-show="selectOpen"
x-ref="selectableItemsList"
{...{
"@click.away": "selectOpen = false",
"x-transition:enter": "transition ease-out duration-50",
"x-transition:enter-start": "opacity-0 -translate-y-1",
"x-transition:enter-end": "opacity-100"
}}
x-bind:class="{ 'bottom-0 mb-10' : selectDropdownPosition == 'top', 'top-0 mt-10' : selectDropdownPosition == 'bottom' }"
class="absolute bg-background text-foreground flex flex-col z-[1] w-full grow py-1 mt-1 overflow-y-auto text-sm rounded-md shadow-md max-h-56"
x-cloak="true"
>
<template x-for="item in selectableItems" x-bind:key="item.value">
<li
x-on:click="selectedItem = item; selectOpen = false; $refs.selectButton.focus(); $dispatch('select', item)"
x-bind:id="item.value + '-' + selectId"
x-bind:data-disabled="item.disabled ?? false"
x-on:mousemove="selectableItemActive = item"
class="relative flex items-center h-full py-2 pr-2 pl-8 cursor-pointer select-none hover:bg-base/30 data-[disabled]:bg-base-light data-[disabled]:text-base-dark data-[disabled]:pointer-events-none data-[disabled]:pointer-not-allowed"
>
<Icon
name="ri.check-line"
x-show="selectedItem?.value == item.value"
class="absolute left-0 size-4 ml-2 stroke-current text-nmuted-foreground"
/>
<span class="block font-medium truncate" x-text="item.label"></span>
</li>
</template>
</ul>
</div>
);
}
-------------------- Pagination Component -------------------------
/**
* @typedef {Object} PaginationProps
* @type {{ selectedPage?: number, pages: number, firstButtonLabel?: string, previousButtonLabel?: string, nextButtonLabel?: string, lastButtonLabel?: string, customFirstButton?: JSX.Element, customPreviousButton?: JSX.Element, customNextButton?: JSX.Element, customLastButton?: JSX.Element } & import("../common/props").HTMLTag}
*/
import { Button } from "./button.component";
import { Icon } from "./icon.component";
import { NumberInput } from "./input.component";
import { Select } from "./select.component";
import clsx from "clsx";
/**
* @typedef {Object} InputPaginationProps
* @type {PaginationProps & Omit<import("./input.component").InputProps, "class">}
*/
/**
* @typedef {Object} SelectPaginationProps
* @type {PaginationProps & Omit<import("./input.component").SelectInputProps, "class">}
*/
/**
* Pagination component props
* @type {import("../common/props").JSXComponent<PaginationProps>}
*/
export function Pagination(props) {
const {
children,
class: className,
firstButtonLabel,
previousButtonLabel,
nextButtonLabel,
lastButtonLabel,
pages,
selectedPage,
customFirstButton,
customLastButton,
customNextButton,
customPreviousButton,
...restProps
} = props;
return (
<div
x-data={`pagination(${pages}, ${selectedPage})`}
class={clsx("flex items-center gap-x-2", className)}
{...restProps}
>
{customFirstButton ?? (
<Button x-on:click="selectFirstPage" x-bind:disabled="isFirstPage">
{firstButtonLabel ? (
<span safe>{firstButtonLabel}</span>
) : (
<Icon name="ri.arrow-left-double-line" />
)}
</Button>
)}
{customPreviousButton ?? (
<Button x-on:click="selectPreviousPage" x-bind:disabled="isFirstPage">
{previousButtonLabel ? (
<span safe>{previousButtonLabel}</span>
) : (
<Icon name="ri.arrow-left-s-line" />
)}
</Button>
)}
{children}
{customNextButton ?? (
<Button x-on:click="selectNextPage" x-bind:disabled="isLastPage">
{nextButtonLabel ? (
<span safe>{nextButtonLabel}</span>
) : (
<Icon name="ri.arrow-right-s-line" />
)}
</Button>
)}
{customLastButton ?? (
<Button x-on:click="selectLastPage" x-bind:disabled="isLastPage">
{lastButtonLabel ? (
<span safe>{lastButtonLabel}</span>
) : (
<Icon name="ri.arrow-right-double-line" />
)}
</Button>
)}
</div>
);
}
/**
* Input Pagination component props
* @type {import("../common/props").JSXComponent<InputPaginationProps>}
*/
export function InputPagination(props) {
const { class: className, pages, ...restProps } = props;
return (
<Pagination class={className} pages={pages} {...restProps}>
<div class="flex items-center gap-x-2">
<NumberInput
x-init="value = selectedPage"
x-bind:value="selectedPage"
max={pages}
x-on:input="selectPage(Number($event.target.value))"
/>
<span>/</span>
<span x-text="pages"></span>
</div>
</Pagination>
);
}
/**
* Select Pagination component props
* @type {import("../common/props").JSXComponent<SelectPaginationProps>}
*/
export function SelectPagination(props) {
const { class: className, pages, ...restProps } = props;
return (
<Pagination class={className} pages={pages} {...restProps}>
<div class="flex items-center gap-x-2">
<Select
x-effect="selectedItem = { value: selectedPage, label: selectedPage }"
x-init={`
$watch('selectOpen', () => {
selectedItem = { value: selectedPage, label: selectedPage };
})
`}
items={Array.from({ length: pages }, (_, index) => ({
value: String(index + 1),
label: String(index + 1)
}))}
x-on:select="selectPage(Number($event.detail.value))"
class="input"
/>
<span>/</span>
<span x-text="pages"></span>
</div>
</Pagination>
);
}
-------------------- Alpine Dependencies -------------------------
/**
* @typedef {Object} PaginationDataOutput
* @property {number} selectedPage
* @property {number} pages
* @property {Function} selectFirstPage
* @property {Function} selectLastPage
* @property {Function} selectPreviousPage
* @property {Function} selectNextPage
* @property {(page: number) => void} selectPage
* @property {() => boolean} isFirstPage
* @property {() => boolean} isLastPage
*/
/**
* Pagination alpine data
* @param {number} pages
* @param {number} selectedPage
* @returns {import("alpinejs").AlpineComponent<PaginationDataOutput>}
*/
export function paginationData(pages, selectedPage = 1) {
return {
selectedPage,
pages,
selectFirstPage() {
this.selectedPage = 1;
},
selectLastPage() {
this.selectedPage = this.pages;
},
selectPreviousPage() {
this.selectedPage -= 1;
},
selectNextPage() {
this.selectedPage += 1;
},
selectPage(page) {
if (page > this.pages) {
this.selectLastPage();
} else if (page < 1) {
this.selectFirstPage();
} else {
this.selectedPage = page;
}
},
isFirstPage() {
return this.selectedPage === 1;
},
isLastPage() {
return this.selectedPage === this.pages;
},
};
}
Input Pagination
Input Pagination is a set of input type number and buttons.
By changing the intput number, you get back this value and can perform a navigation.
Copied !
import { InputPagination } from "$components/pagination.component";
export function InputPaginationExample() {
return (
<InputPagination
x-init={`
$watch("selectedPage", (value) => {
console.log({ selectedPage: value });
})
`}
pages={20}
class="[&_input]:w-24 text-slate-900"
selectedPage={3}
/>
);
}
Select Pagination
Select Pagination is Select component instead of input. The pages number is display in the select list.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
Copied !
import { SelectPagination } from "$components/pagination.component";
export function SelectPaginationExample() {
return (
<SelectPagination
x-init={`
$watch("selectedPage", (value) => {
console.log({ selectedPage: value });
})
`}
pages={20}
class="[&_input]:w-24 text-slate-900"
selectedPage={3}
/>
);
}
Custom Button Label
Pagination Pagination has 4 props to change the 4 buttons label:firstButtonlabel, previousButtonLabel, nextButtonLabel and lastButtonLabel.
By default, icons are displayed.
Copied !
import { InputPagination } from "$components/pagination.component";
export function CustomLabelPaginationExample() {
return (
<InputPagination
x-init={`
$watch("selectedPage", (value) => {
console.log({ selectedPage: value });
})
`}
class={"text-slate-900"}
pages={10}
firstButtonLabel="First"
previousButtonLabel="Previous"
nextButtonLabel="Next"
lastButtonLabel="Last"
/>
);
}
Custom Button
You can even change the 4 buttons design. Check example below to know how to do it.
- 1
- 2
- 3
Copied !
import { PrimaryButton } from "$components/button.component";
import { SelectPagination } from "$components/pagination.component";
export function CustomButtonPaginationExample() {
return (
<SelectPagination
x-init={`
$watch("selectedPage", (value) => {
console.log({ selectedPage: value });
})
`}
pages={3}
class="[&_input]:w-24 text-slate-900"
selectedPage={3}
customFirstButton={
<PrimaryButton
x-bind:disabled="isFirstPage"
x-on:click="selectFirstPage"
text="Première"
/>
}
customPreviousButton={
<PrimaryButton
x-bind:disabled="isFirstPage"
x-on:click="selectPreviousPage"
text="Précédente"
/>
}
customNextButton={
<PrimaryButton
x-bind:disabled="isLastPage"
x-on:click="selectNextPage"
text="Suivante"
/>
}
customLastButton={
<PrimaryButton
x-bind:disabled="isLastPage"
x-on:click="selectLastPage"
text="Dernière"
/>
}
/>
);
}