Esikatselu
<Pagination aria-label="Sivutus">
<PaginationGroup>
<PaginationButton previous disabled aria-label="Edellinen sivu" />
<PaginationButton active>1</PaginationButton>
<PaginationButton>2</PaginationButton>
<PaginationButton>3</PaginationButton>
<PaginationButton>4</PaginationButton>
<PaginationButton next aria-label="Seuraava sivu" />
</PaginationGroup>
</Pagination>
Käyttötarkoitus
Sivutuksen avulla voit jakaa pitkät listat asiakkaan kannalta kohtuullisen pituisiin
näkymiin. Voit jakaa esimerkiksi pitkän taulukkonäkymän tai hakutuloslistan
useaan näkymään, jolloin yhden osion tietosisältöä on helpompi silmäillä. Sivutuksen
avulla asiakas voi myös siirtyä sivulta toiselle.
Sivutuksen suunnitteluun vaikuttavat asiakkaan tarpeet ja käyttötilanne. Suunnittele
sivutus kyseiseen tilanteeseen sopivaksi käyttämällä sivutuskomponentin tarjoamia
vaihtoehtoja.
Mieti sivutuksen yhteydessä, kuinka paljon tietoa kannattaa kerralla näyttää.
Asiakas ei saa joutua vaihtamaan sivua tarpeettoman moneen kertaan. Toisaalta
pitkien listausten lataamisessa pitää huomioida myös järjestelmän suorituskyky.
Huomioi myös näytettävien tietojen järjestys. Jos asiakkaan kannalta oleellisimmat
tiedot näytetään heti listauksen alussa, tarve sivujen vaihtamiselle
vähenee.
- Suunnittele sivutus sisällön ja käyttötilanteen ehdoilla.
- Näytä aina, millä sivulla asiakas on.
- Näytä aina sivujen kokonaismäärä, jos se on teknisesti mahdollista.
- Tarjoa tarvittaessa Näytä kaikki -toiminto.
- Sijoita sivutus asiakkaan kannalta järkevään paikkaan.
- Anna asiakkaan tarvittaessa valita sivulla näytettävien kohteiden määrä..
- Varmista, että sivutus toimii myös pienellä näytöllä. Suunnittele tarvittaessa pienelle näytölle erilainen sivutus.
- Anna sivujen selaamisesta selkeä palaute myös ruudunlukijoille.
- Älä näytä sivutusta, jos kaikki tiedot mahtuvat helposti samaan näkymään.
- Vältä turhaa sivutusta. Jos tietojen määrä on kohtuullinen, sisältöä on usein helpompi selailla alaspäin vierittämällä.
- Vältä tilannetta, jossa yhdelle sivulle jäisi vain muutama näytettävä tieto. Näytä tällöin kaikki tiedot samassa näkymässä.
- Älä tarjoa sivutusta ainoana keinona tiedon löytämiseen. Tarjoa myös esimerkiksi hakutoiminto tai mahdollisuus tietojen suodattamiseen tai järjestämiseen.
Saavutettavuus
Varmista, että valittu sivutuskomponentti mahtuu tarvittaessa myös pienelle näytölle. Voit myös käyttää pienellä näytöllä erilaista sivutusta.
Pagination
-komponentti renderöi <nav>
-elementin. Muista kertoa ruudunlukijan käyttäjille mistä navigaatioelementissä on kyse
aria-label
-attribuutilla niin, että asiakas ymmärtää mitä sivulla olevia sisältöjä sivutus koskee.
Korosta aktiivisen sivun PaginationButton
aina käyttämällä sivun korostusta active
-propilla. Tämä korostaa painikkeen visuaalisesti
ja lisää painikkeelle aina aria-current="page"
-attribuutin automaattisesti.
Pudotusvalikossa olevalle sivulle aria-current="page"
pitää asettaa itse, sillä se ei yleiskäyttöisenä komponenttina aseta tätä automaattisesti.
Jos sivutuksen eri sivuille on mahdollista linkittää tai sivun vaihtaminen päivittää osoitetta, kannattaa muuttaa sivutuksen painikkeet linkeiksi.
Katso esimerkki kohdasta Sivutuksen toteutus linkkeinä. Kannattaa huomioida myös selaimen eteen- ja taaksepäin-painikkeiden toiminta.
Sivutustyypit
Valitse sivutustyyppi käyttökontekstin, asiakkaan tarpeiden ja käytettävissä olevan tilan mukaan. Sivutuskomponentti
tarjoaa sivutuksen toteutukseen erilaisia painikkeita, joiden avulla voit rakentaa halutun sivutuksen.
Sivutuskomponentti koostuu useasta pienemmästä komponentista:
Pagination
- Container-komponentti, jonka sisälle sivutus toteutetaan.
PaginationGroup
- Komponentti, jonka avulla painikkeita ja tekstejä voi ryhmitellä loogisiin kokonaisuuksiin.
PaginationButton
- Painike- tai linkkielementti yksittäisen sivun esittämiseen.
PaginationText
- Sivutukseen liittyvät aputekstit, esim. näytettävien tietojen lukumäärä.
Sivunumerot
Käytä sivunumeroita, jotta asiakas voi selata sivuja järjestyksessä.
Sivunumerot sopivat myös tilanteeseen, jossa sivuja on vähän, ja kaikki sivunumerot
mahtuvat samaan näkymään. Asiakas voi siirtyä edelliselle tai seuraavalla sivulle
nuolipainikkeella tai klikata haluamansa sivun numeroa.
Jos edelliselle tai seuraavalle sivulle ei voi siirtyä, älä piilota painikkeita,
vaan estä painikkeen käyttö disabled
-attribuutilla.
Voit näyttää sivuja niin monta kuin niitä näytölle mahtuu. Älä kuitenkaan rivitä sivunumeroita.
<Pagination aria-label="Sivutus">
<PaginationGroup>
<PaginationButton previous disabled aria-label="Edellinen sivu" />
<PaginationButton active>1</PaginationButton>
<PaginationButton>2</PaginationButton>
<PaginationButton>3</PaginationButton>
<PaginationButton>4</PaginationButton>
<PaginationButton next aria-label="Seuraava sivu" />
</PaginationGroup>
</Pagination>
Jos sivuja on paljon, kaikki sivunumerot eivät välttämättä mahdu samaan näkymään.
Tällöin sivuja voi piilottaa ja korvata ne kolmella pisteellä käyttämällä PaginationText
-komponentin more
-proppia.
Ruudunlukijoille voi antaa kolmea pistettä paremmin kuvaavan tekstin srOnlyText
-propilla.
Näytä kuitenkin aina ensimmäinen sivu, viimeinen sivu, valittu sivu ja sitä edeltävät ja seuraavat 1-2
sivua (käytettävissä olevasta tilasta riippuen).
Jos tila ei riitä sivujen piilottamisesta huolimatta (esim. pienellä näytöllä),
älä rivitä painikkeita vaan käytä mieluummin pudotusvalikkoa (ks. esimerkit alla).
Sivutus, kun asiakas on ensimmäisellä sivulla.
<Pagination aria-label="Sivutus">
<PaginationGroup>
<PaginationButton previous disabled aria-label="Edellinen sivu" />
<PaginationButton active>1</PaginationButton>
<PaginationButton>2</PaginationButton>
<PaginationButton>3</PaginationButton>
<PaginationButton>4</PaginationButton>
<PaginationButton>5</PaginationButton>
<PaginationText more srOnlyText="Muut sivut" />
<PaginationButton>20</PaginationButton>
<PaginationButton next aria-label="Seuraava sivu" />
</PaginationGroup>
</Pagination>
Sivutus, kun asiakas on sivujoukon keskellä olevalla sivulla.
<Pagination aria-label="Sivutus">
<PaginationGroup>
<PaginationButton previous aria-label="Edellinen sivu" />
<PaginationButton>1</PaginationButton>
<PaginationText more srOnlyText="Muut sivut" />
<PaginationButton>9</PaginationButton>
<PaginationButton active>10</PaginationButton>
<PaginationButton>11</PaginationButton>
<PaginationText more srOnlyText="Muut sivut" />
<PaginationButton>20</PaginationButton>
<PaginationButton next aria-label="Seuraava sivu" />
</PaginationGroup>
</Pagination>
Sivutus, kun asiakas on viimeisellä sivulla.
<Pagination aria-label="Sivutus">
<PaginationGroup>
<PaginationButton previous aria-label="Edellinen sivu" />
<PaginationButton>1</PaginationButton>
<PaginationText more srOnlyText="Muut sivut" />
<PaginationButton>16</PaginationButton>
<PaginationButton>17</PaginationButton>
<PaginationButton>18</PaginationButton>
<PaginationButton>19</PaginationButton>
<PaginationButton active>20</PaginationButton>
<PaginationButton next disabled aria-label="Seuraava sivu" />
</PaginationGroup>
</Pagination>
Jos sivujen kokonaismäärää ei tiedetä, sivun viimeisen painikkeen voi korvata kolmella pisteellä käyttämällä PaginationText
-komponenttia ja more
-propia.
<Pagination aria-label="Sivutus">
<PaginationGroup>
<PaginationButton previous aria-label="Edellinen sivu" />
<PaginationButton>1</PaginationButton>
<PaginationText more srOnlyText="Muut sivut" />
<PaginationButton>9</PaginationButton>
<PaginationButton active>10</PaginationButton>
<PaginationButton>11</PaginationButton>
<PaginationText more srOnlyText="Muut sivut" />
<PaginationButton next aria-label="Seuraava sivu" />
</PaginationGroup>
</Pagination>
Pudotusvalikko
Jos sivutettavaa sisältöä on paljon tai jos asiakas ei välttämättä selaa sisältöä
järjestyksessä, kannattaa tarjota mahdollisuus siirtyä suoraan tietylle sivulle
käyttämällä pudotusvalikkoa. Pudotusvalikko sopii myös tilanteisiin, joissa
käytettävissä olevaa tilaa on vain vähän (esimerkiksi pienellä näytöllä). Näytä
pudotusvalikon lisäksi aina myös edellinen- ja seuraava-painikkeet.
const DemoPagination = () => {
const { isToggleOn: isOpen, flipToggle: toggleDropdown } = useToggle();
return (
<Pagination aria-label="Sivutus">
<PaginationGroup>
<PaginationButton previous disabled aria-label="Edellinen" />
<Dropdown isOpen={isOpen("demo")} onClick={() => toggleDropdown("demo")}>
<DropdownToggle as={PaginationButton} caret>
Sivu 1/20
</DropdownToggle>
<DropdownMenu className="kds-overflow-auto" style={{ maxHeight: "20rem" }}>
<DropdownMenuGroup>
{Array(20)
.fill(1)
.map((x, i) => (
<DropdownMenuItem key={i} active={i === 0} as="button">
{`Sivu ${i + 1}`}
</DropdownMenuItem>
))}
</DropdownMenuGroup>
</DropdownMenu>
</Dropdown>
<PaginationButton next aria-label="Seuraava" />
</PaginationGroup>
</Pagination>
);
};
render(<DemoPagination />);
Jos sivujen kokonaismäärää ei tiedetä, sivutuksessa näytetään siirtymät edelliselle, seuraavalle ja ensimmäiselle sivulle.
Lisäksi pudotusvalikon tilalla näytetään nykyisen sivun numero.
Sivutus, kun asiakas on ensimmäisellä sivulla.
<Pagination aria-label="Sivutus">
<PaginationGroup>
<PaginationButton disabled previous aria-label="Edellinen" />
<PaginationText>Sivu 1</PaginationText>
<PaginationButton next aria-label="Seuraava" />
</PaginationGroup>
</Pagination>
Sivutus, kun asiakas on muulla kuin ensimmäisellä sivulla.
<Pagination aria-label="Sivutus">
<PaginationGroup>
<PaginationButton previous aria-label="Edellinen" />
<PaginationButton>1</PaginationButton>
<PaginationText>Sivu 4</PaginationText>
<PaginationButton next aria-label="Seuraava" />
</PaginationGroup>
</Pagination>
Yhdistelmä
Tarvittaessa voit yhdistellä komponenteista kokonaisuuden, joka vastaa asiakkaan tarpeisiin.
Näytä ensin sivun vaihtamiseen tarkoitetut painikkeet ja sen jälkeen mahdolliset sivutukseen liittyvät tekstimuotoiset lisätiedot. Esitä lopuksi muut sivutustoiminnot (esim. yhdellä sivulla näytettävien tietojen lukumäärä).
const DemoPagination = () => {
const { isToggleOn: isOpen, flipToggle: toggleDropdown } = useToggle();
return (
<Pagination aria-label="Sivutus">
<PaginationGroup>
<PaginationButton previous disabled aria-label="Edellinen sivu" />
<Dropdown isOpen={isOpen("jump-to-page")} onClick={() => toggleDropdown("jump-to-page")}>
<DropdownToggle as={PaginationButton} caret>
Sivu 1/37
</DropdownToggle>
<DropdownMenu className="kds-overflow-auto" style={{ maxHeight: "20rem" }}>
<DropdownMenuGroup>
{Array(37)
.fill(1)
.map((x, i) => (
<DropdownMenuItem as="button" active={i === 0} key={i}>
{`Sivu ${i + 1}`}
</DropdownMenuItem>
))}
</DropdownMenuGroup>
</DropdownMenu>
</Dropdown>
<PaginationButton next aria-label="Seuraava sivu" />
</PaginationGroup>
<PaginationGroup>
<PaginationText>Rivit 1-50, yhteensä 1850</PaginationText>
</PaginationGroup>
<PaginationGroup>
<Dropdown isOpen={isOpen("items-per-page")} onClick={() => toggleDropdown("items-per-page")}>
<DropdownToggle as={PaginationButton} caret>
50/sivu
</DropdownToggle>
<DropdownMenu>
<DropdownMenuItem active as="button">
50/sivu
</DropdownMenuItem>
<DropdownMenuItem as="button">100/sivu</DropdownMenuItem>
<DropdownMenuItem as="button">200/sivu</DropdownMenuItem>
<DropdownMenuItem divider />
<DropdownMenuItem as="button">Näytä kaikki</DropdownMenuItem>
</DropdownMenu>
</Dropdown>
</PaginationGroup>
</Pagination>
);
};
render(<DemoPagination />);
const DemoPagination = () => {
const { isToggleOn: isOpen, flipToggle: toggleDropdown } = useToggle();
return (
<Pagination aria-label="Sivutus">
<PaginationGroup>
<PaginationButton previous disabled aria-label="Edellinen sivu" />
<PaginationButton active>1</PaginationButton>
<PaginationButton>2</PaginationButton>
<PaginationButton>3</PaginationButton>
<PaginationButton>4</PaginationButton>
<PaginationButton>5</PaginationButton>
<PaginationText more />
<PaginationButton>20</PaginationButton>
<PaginationButton next aria-label="Seuraava sivu" />
</PaginationGroup>
<PaginationGroup>
<Dropdown isOpen={isOpen("jump-to-page")} onClick={() => toggleDropdown("jump-to-page")}>
<DropdownToggle as={PaginationButton} caret>
Sivu 1/20
</DropdownToggle>
<DropdownMenu className="kds-overflow-auto" style={{ maxHeight: "20rem" }}>
<DropdownMenuGroup>
{Array(20)
.fill(1)
.map((x, i) => (
<DropdownMenuItem as="button" active={i === 0} key={i}>
{`Sivu ${i + 1}`}
</DropdownMenuItem>
))}
</DropdownMenuGroup>
</DropdownMenu>
</Dropdown>
</PaginationGroup>
</Pagination>
);
};
render(<DemoPagination />);
Näytettävien tietojen lukumäärä
Tarvittaessa voit antaa asiakkaan valita, kuinka paljon tietoa näkymässä kerrallaan
näytetään. Aseta oletusvalinta niin, että se soveltuu useimpiin tilanteisiin eikä sitä tarvitse joka kerta vaihtaa.
Toteuta valikon porrastus siten, että valinnan muuttamisella on oikeasti merkitystä.
Esimerkiksi 20 - 50 - 100 on merkityksellisempi porrastus kuin 10 - 20 - 30. Älä kuitenkaan
tarjoa liikaa vaihtoehtoja, jotta kokonaisuus säilyy selkeänä.
Asiakkaalle voi tarjota Näytä kaikki -toiminnallisuuden, jos järjestelmän suorituskyky
mahdollistaa sen (Esim. 20 - 50 - 100 - Kaikki). Huomioi kuitenkin aina myös se, kuinka paljon
tietoa asiakkaan näytölle mahtuu.
Sivutettujen tietojen kokonaismäärän ja muut sivutusta tukevat aputekstit voi toteuttaa PaginationText
-komponentilla.
const DemoPagination = () => {
const { isToggleOn: isOpen, flipToggle: toggleDropdown } = useToggle();
return (
<Pagination aria-label="Sivutus">
<PaginationGroup>
<PaginationButton previous disabled aria-label="Edellinen sivu" />
<Dropdown isOpen={isOpen("jump-to-page")} onClick={() => toggleDropdown("jump-to-page")}>
<DropdownToggle as={PaginationButton} caret>
Sivu 1/37
</DropdownToggle>
<DropdownMenu className="kds-overflow-auto" style={{ maxHeight: "20rem" }}>
<DropdownMenuGroup>
{Array(37)
.fill(1)
.map((x, i) => (
<DropdownMenuItem as="button" active={i === 0} key={i}>
{`Sivu ${i + 1}`}
</DropdownMenuItem>
))}
</DropdownMenuGroup>
</DropdownMenu>
</Dropdown>
<PaginationButton next aria-label="Seuraava sivu" />
</PaginationGroup>
<PaginationGroup>
<PaginationText>Rivit 1-50, yhteensä 1850</PaginationText>
</PaginationGroup>
<PaginationGroup>
<Dropdown isOpen={isOpen("items-per-page")} onClick={() => toggleDropdown("items-per-page")}>
<DropdownToggle as={PaginationButton} caret>
50/sivu
</DropdownToggle>
<DropdownMenu>
<DropdownMenuItem active as="button">
50/sivu
</DropdownMenuItem>
<DropdownMenuItem as="button">100/sivu</DropdownMenuItem>
<DropdownMenuItem as="button">200/sivu</DropdownMenuItem>
<DropdownMenuItem divider />
<DropdownMenuItem as="button">Näytä kaikki</DropdownMenuItem>
</DropdownMenu>
</Dropdown>
</PaginationGroup>
</Pagination>
);
};
render(<DemoPagination />);
Sijainti ja ryhmittely
Sivutus tasataan oletuksena vasempaan reunaan.
<Pagination aria-label="Sivutus">
<PaginationGroup>
<PaginationButton previous disabled aria-label="Edellinen sivu" />
<PaginationButton active>1</PaginationButton>
<PaginationButton>2</PaginationButton>
<PaginationButton>3</PaginationButton>
<PaginationButton>4</PaginationButton>
<PaginationButton>5</PaginationButton>
<PaginationText more />
<PaginationButton>20</PaginationButton>
<PaginationButton next aria-label="Seuraava sivu" />
</PaginationGroup>
</Pagination>
Kaksipalstaisen lomakeasettelun yhteydessä esiintyvän taulukon sivutuspainikkeet tasataan oikealle samoin kuin lomakkeen painikkeet.
const DemoPagination = () => {
const { isToggleOn: isOpen, flipToggle: toggleDropdown } = useToggle();
return (
<>
<Table size="sm">
<TableHead>
<TableRow>
<TableHeader>Lorem ipsum</TableHeader>
<TableHeader>Sed posuere</TableHeader>
<TableHeader>Quisque ligula</TableHeader>
<TableHeader align="numeric">Status</TableHeader>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell>
<Link href="#">123</Link>
</TableCell>
<TableCell>Nam molestie nec tortor</TableCell>
<TableCell>Donec placerat leo sit amet velit</TableCell>
<TableCell align="numeric">
<Badge variant="success" />
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Link href="#">456</Link>
</TableCell>
<TableCell>Nam molestie nec tortor</TableCell>
<TableCell>Donec placerat leo sit amet velit</TableCell>
<TableCell align="numeric">
<Badge variant="success" />
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Link href="#">789</Link>
</TableCell>
<TableCell>Nam molestie nec tortor</TableCell>
<TableCell>Donec placerat leo sit amet velit</TableCell>
<TableCell align="numeric">
<Badge variant="danger" />
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Link href="#">012</Link>
</TableCell>
<TableCell>Nam molestie nec tortor</TableCell>
<TableCell>Donec placerat leo sit amet velit</TableCell>
<TableCell align="numeric">
<Badge variant="success" />
</TableCell>
</TableRow>
</TableBody>
</Table>
<Pagination aria-label="Sivutus" className="kds-justify-end">
<PaginationGroup>
<PaginationButton previous disabled aria-label="Edellinen sivu" />
<Dropdown isOpen={isOpen("jump-to-page")} onClick={() => toggleDropdown("jump-to-page")}>
<DropdownToggle as={PaginationButton} caret>
Sivu 1/37
</DropdownToggle>
<DropdownMenu className="kds-overflow-auto" style={{ maxHeight: "20rem" }}>
<DropdownMenuGroup>
{Array(37)
.fill(1)
.map((x, i) => (
<DropdownMenuItem as="button" active={i === 0} key={i}>
{`Sivu ${i + 1}`}
</DropdownMenuItem>
))}
</DropdownMenuGroup>
</DropdownMenu>
</Dropdown>
<PaginationButton next aria-label="Seuraava sivu" />
</PaginationGroup>
<PaginationGroup>
<PaginationText>Rivit 1-50, yhteensä 1850</PaginationText>
</PaginationGroup>
<PaginationGroup>
<Dropdown isOpen={isOpen("items-per-page")} onClick={() => toggleDropdown("items-per-page")}>
<DropdownToggle as={PaginationButton} caret>
50/sivu
</DropdownToggle>
<DropdownMenu>
<DropdownMenuItem active as="button">
50/sivu
</DropdownMenuItem>
<DropdownMenuItem as="button">100/sivu</DropdownMenuItem>
<DropdownMenuItem as="button">200/sivu</DropdownMenuItem>
<DropdownMenuItem divider />
<DropdownMenuItem as="button">Näytä kaikki</DropdownMenuItem>
</DropdownMenu>
</Dropdown>
</PaginationGroup>
</Pagination>
</>
);
};
render(<DemoPagination />);
Sivutus esitetään oletuksena aina listan alapuolella. Joissain tilanteissa (esim.
pitkät hakutuloslistaukset) sivutus voidaan tarvittaessa esittää myös listan yläpuolella.
Listan yläpuolelle sijoitetussa sivutuksessa kannattaa huomioida asiakkaan käyttökokemus. Selvitä, onko asiakkaalla tarve selata listan näkyvä sivu loppuun ennen seuraalle sivulle siirtymistä.
Sivutus voi koostua useasta toiminnosta tai toimintoryhmästä. Yksittäisen toimintoryhmän sisällä olevien
painikkeiden välissä on aina 8px tyhjää tilaa. Erillisten toimintoryhmien välissä tilaa on 24px, jolloin erilaiset toiminnot erottuvat toisistaan selkeästi.
Aseta sivutuksen komponentit aina PaginationGroup
-komponentin sisälle ja luo sillä tarvittavat toimintoryhmät Pagination
-komponentin sisälle. PaginationGroup
asettaa komponenttiryhmille automaattisesti
halutun välistyksen.
Koodiesimerkit sivutuksen toteutukseen
Sivutuksen toteuttamiseen voi hyödyntää usePagination-hookkia.
Normaali sivutus
const UsePaginationExample = () => {
const [isOpen, setIsOpen] = useState(false);
const { pages, totalPages, currentPage, changePage, nextPage, previousPage, isPrevious, isNext } = usePagination({
initialPage: 1,
itemsPerPage: 10,
totalItems: 248,
});
return (
<Pagination aria-label="Sivutus">
<PaginationGroup>
<PaginationButton
aria-label="Edellinen"
disabled={!isPrevious}
onClick={() => changePage(previousPage)}
previous
/>
{pages.map(({ page, more }) => {
const key = `pagination-button-${page}`;
if (more) {
return <PaginationText key={key} className="kds-hidden sm:kds-inline-block" more />;
}
return (
<PaginationButton
key={key}
active={currentPage === page}
onClick={() => changePage(page)}
className={clsx({ "kds-hidden sm:kds-inline-block": page !== currentPage })}
>
{page}
</PaginationButton>
);
})}
<PaginationButton aria-label="Seuraava" disabled={!isNext} onClick={() => changePage(nextPage)} next />
</PaginationGroup>
<PaginationGroup>
<Dropdown isOpen={isOpen} onClick={() => setIsOpen(!isOpen)}>
<DropdownToggle as={PaginationButton} caret>
Sivu {currentPage}/{totalPages}
</DropdownToggle>
<DropdownMenu className="kds-overflow-auto" style={{ maxHeight: "20rem" }}>
<DropdownMenuGroup>
{[...Array(totalPages).keys()].map((i) => (
<DropdownMenuItem
onClick={() => changePage(i + 1)}
as="button"
active={currentPage === i + 1}
aria-current={currentPage === i + 1 ? "page" : undefined}
key={`pagination-dropdown-item-${i}`}
>
Sivu {i + 1}
</DropdownMenuItem>
))}
</DropdownMenuGroup>
</DropdownMenu>
</Dropdown>
</PaginationGroup>
</Pagination>
);
};
render(<UsePaginationExample />);
Näytettävien tietojen lukumäärän muuttaminen
const UsePaginationExample = () => {
const totalItems = 1850;
const perPageOptions = [25, 50, 100, 200];
const [isOpen, setIsOpen] = useState(false);
const [isLimitOpen, setIsLimitOpen] = useState(false);
const [itemsPerPage, setItemsPerPage] = useState(perPageOptions[0]);
const { pages, totalPages, currentPage, changePage, nextPage, previousPage, isPrevious, isNext, resultsFrom, resultsTo } = usePagination({
initialPage: 1,
itemsPerPage,
totalItems,
more: false,
});
const handlePerPageChange = (perPage: number) => {
changePage(1);
setItemsPerPage(perPage);
}
return (
<Pagination aria-label="Sivutus">
<PaginationGroup>
<PaginationButton
aria-label="Edellinen"
disabled={!isPrevious}
onClick={() => changePage(previousPage)}
previous
/>
<Dropdown isOpen={isOpen} onClick={() => setIsOpen(!isOpen)}>
<DropdownToggle as={PaginationButton} caret>
Sivu {currentPage}/{totalPages}
</DropdownToggle>
<DropdownMenu className="kds-overflow-auto" style={{ maxHeight: "20rem" }}>
<DropdownMenuGroup>
{pages.map(({ page }) => (
<DropdownMenuItem
as="button"
active={page === currentPage}
key={`pagination-button-${page}`}
onClick={() => changePage(page)}
>
{`Sivu ${page}`}
</DropdownMenuItem>
))}
</DropdownMenuGroup>
</DropdownMenu>
</Dropdown>
<PaginationButton aria-label="Seuraava" disabled={!isNext} onClick={() => changePage(nextPage)} next />
</PaginationGroup>
<PaginationGroup>
<PaginationText>
Rivit {resultsFrom}-{resultsTo}, yhteensä {totalItems}
</PaginationText>
</PaginationGroup>
<PaginationGroup>
<Dropdown isOpen={isLimitOpen} onClick={() => setIsLimitOpen(!isLimitOpen)}>
<DropdownToggle as={PaginationButton} caret>
{itemsPerPage}/sivu
</DropdownToggle>
<DropdownMenu>
{perPageOptions.map((option) => (
<DropdownMenuItem
active={itemsPerPage === option}
key={`pagination-limit-${option}`}
as="button"
onClick={() => handlePerPageChange(option)}
>
{option}/sivu
</DropdownMenuItem>
))}
</DropdownMenu>
</Dropdown>
</PaginationGroup>
</Pagination>
);
};
render(<UsePaginationExample />);
Sivutuksen toteutus linkkeinä
Esimerkki päivittää osoitteen page
-parametria, kun sivua vaihdetaan. Tämä mahdollistaa myös linkittämisen tietylle sivulle
sekä selaimen takaisin- ja eteenpäin-painikkeiden toiminnan.
Toteutuksessa kannattaa hyödyntää sovelluksen käyttämää routeria.
const UsePaginationExample = () => {
const [isOpen, setIsOpen] = useState(false);
const { pages, totalPages, currentPage, changePage, nextPage, previousPage, isPrevious, isNext } = usePagination({
initialPage: 1,
itemsPerPage: 10,
totalItems: 248,
});
useEffect(() => {
const handleHashChange = () => {
const hash = window.location.hash;
const hashParts = hash.split("#?");
const page = hashParts.find((el) => el.includes("page="))?.replace("page=", "");
changePage(parseInt(page) || 1);
};
handleHashChange();
window.addEventListener("hashchange", handleHashChange);
return () => {
window.removeEventListener("hashchange", handleHashChange);
};
}, []);
return (
<Pagination aria-label="Sivutus">
<PaginationGroup>
{!isPrevious && <PaginationButton aria-label="Edellinen" as="span" disabled previous />}
{isPrevious && <PaginationButton aria-label="Edellinen" as="a" href={`#?page=${previousPage}`} previous />}
{pages.map(({ page, more }) => {
const key = `pagination-button-${page}`;
if (more) {
return <PaginationText key={key} className="kds-hidden sm:kds-inline-block" more />;
}
return (
<PaginationButton
as="a"
key={key}
href={`#?page=${page}`}
active={currentPage === page}
className={clsx({ "kds-hidden sm:kds-inline-block": page !== currentPage })}
>
{page}
</PaginationButton>
);
})}
{!isNext && <PaginationButton aria-label="Seuraava" as="span" disabled next />}
{isNext && <PaginationButton aria-label="Seuraava" as="a" href={`#?page=${nextPage}`} next />}
</PaginationGroup>
<PaginationGroup>
<Dropdown isOpen={isOpen} onClick={() => setIsOpen(!isOpen)}>
<DropdownToggle as={PaginationButton} caret>
Sivu {currentPage}/{totalPages}
</DropdownToggle>
<DropdownMenu className="kds-overflow-auto" style={{ maxHeight: "20rem" }}>
<DropdownMenuGroup>
{[...Array(totalPages).keys()].map((i) => (
<DropdownMenuItem
href={`#?page=${i + 1}`}
active={currentPage === i + 1}
aria-current={currentPage === 1 + 1 ? "page" : undefined}
key={`pagination-dropdown-item-${i}`}
>
Sivu {i + 1}
</DropdownMenuItem>
))}
</DropdownMenuGroup>
</DropdownMenu>
</Dropdown>
</PaginationGroup>
</Pagination>
);
};
render(<UsePaginationExample />);