Pagination
Moves between the pages of a long list or a table.
import com.pantrixui.components.data.pagination.PantrixPagination
- Numbers and gaps. The first and the last
boundaryCountpages are shown, andsiblingCountpages on each side of the page on screen; those between them fold into a gap of three dots. Each is one unless given. A gap stands for two pages at the least: where a single page is left in between, that page itself is shown. Once there are enough pages to fold, the row has as many items whichever page is on screen: near an end, more pages stand on that side. - In a narrow place. A row too narrow for its numbers folds step by step: first it shows fewer pages beside the page on screen, as many as fit; if that does not fit either, fewer pages at its ends, down to one. Where no row of numbers fits it is laid out as previous, "Page 3 of 10" and next. The room is asked for the page on which the row is widest: the row folds the same way on every page, and its layout does not change as the page moves. How it is laid out is decided by the width left to the row, not by the window.
PaginationLayout.Compactasks for the short row at every width. In a place narrower even than its buttons the short row is drawn smaller: its buttons are not cut. - First and last page.
firstAndLast = trueputs one more button outside previous and outside next: one goes to the first page, the other to the last. On the first page the two buttons at the start cannot be pressed, nor the two at the end on the last page. Four buttons leave less room for the numbers. - The page on screen. It is told by its fill and is no button: a press on it reports nothing.
- The ends. Previous cannot be pressed on the first page, nor next on the last. A
pageoutside the pages is taken as the nearest page. ApageCountunder one is taken as one: a list with nothing in it has one page, an empty one, and the row's arrows cannot be pressed. - A row that cannot be pressed.
enabled = falseturns the whole row off: no part of it can be pressed, and the row is drawn in the theme's disabled colours. If the row is turned off while a keyboard's focus is on one of its parts, the focus stays there; when the row is turned on again, the keyboard goes on from where it was. - Sizes.
PaginationStyle.itemSizeis the size of a number, of previous and of next: 40dp on Android, 36dp on iOS, 32dp on desktop and the web. A number too long for it makes its item wider; the icon of previous and of next is 4dp more than half the item.itemShapegives the corners: fully round on Android and iOS, small on desktop and the web.itemGapis the room between two neighbours, and follows the density. The platform's touch target is kept free around every item; the row is as wide as its items, and at least as tall as that target. - Type.
textStyleis the text style of the numbers and of the short row's words, the theme'slabelstyle unless given. A style that makes an item larger does not make its text larger: a large item is given a large type too. - Digits. The numbers, the numbers in the short row's words and the numbers in the names said to a screen reader are written in the digits of the theme's language (
PantrixStrings.digits): in Arabic digits in the Arabic pack.onPageChangereports the same number in every language. - Colours.
PaginationColorspaints the numbers and the short row's words (content), previous, next and the gaps' marks (control), and the fill and the number of the page on screen (selectedContainer,selectedContent) one by one. On a fill, all of a row that is given no colour is in the colour that is written on the fill; the page on screen is told by its fill, a share of that colour. - Right to left. In languages read from right to left the row starts on the right, and the arrows turn round.
- Page size.
PantrixPageSizeis the words "Per page" and, beside them, a select of sizes. The size that is chosen is its caller's: it is given withpageSize, and when another size is chosen it is reported throughonPageSizeChange; choosing the chosen size again reports nothing. The sizes are 10, 25, 50 and 100 unless given (DefaultPageSizes);pageSizesgives others. ApageSizethat is none of the sizes is shown as chosen too, and stands in the list before the first size larger than itself. The select is as wide as the longest size needs: the row stands still as the choice changes. - Go to page.
PantrixPageJumpis the words "Go to page" and, beside them, a short field. Enter, or the action of a keyboard on the screen, reports the page that was typed throughonPageChangeand empties the field; the focus stays in the field. A number outside the pages is taken as the nearest page; an empty field reports nothing. The field takes digits alone, the Western ones and those of the theme's language, and holds as many digits as the last page's number has. - The companions' words. In both the words stand before the control, on the side where the row starts, and are for the eye: a screen reader is given one control, named by those words.
labelchanges the words. In a narrow place the words give way and the control does not.enabled = falsewrites the words in the disabled text colour and turns the control off. - Automation. A row given a
tagKeyisPagination_<tagKey>, and its parts are named inside it:Pagination_orders.Page_4,Pagination_orders.Step_previous,Pagination_orders.Step_next,Pagination_orders.Step_first,Pagination_orders.Step_last, and the short row's wordsPagination_orders.Text_position. Every page that is asked for is reported asselect, with its number and with what asked for it (page,previous,next,first,last). The companions arePageSize_<tagKey>andPageJump_<tagKey>; the select in one carries the tagSelect_<tagKey>_page_size, the field in the otherTextField_<tagKey>_page_jump.
Examples
Moving between pages
At its plainest: the page on screen (page), how many pages there are (pageCount) and what happens when a page is asked for (onPageChange). Which page the app is on is the screen's state; the row does not hold it: it reports the number of the page that was asked for, and shows it once page says so.
Press a number, or one of the arrows at the two ends: the page that was asked for is written on the card's "Last event" line. The page on screen has a fill and is no button: a press on it reports nothing. Previous cannot be pressed on the first page, nor next on the last.
There are ten pages: the row shows the first and the last, the one on screen and the ones on its two sides, and folds those between into a gap of three dots. On a phone held upright that much does not fit. There the row, by the phone's width, either shows fewer numbers or is in its short form: previous, "Page 1 of 10" and next.
val report = LocalExampleEvents.current
var page by rememberSaveable { mutableIntStateOf(1) }
PantrixPagination(
page = page,
pageCount = 10,
onPageChange = { asked ->
page = asked
report("Page $asked was asked for")
},
tagKey = "plain"
)
A list shown a page at a time
A list of forty-eight orders, five to a page: that makes ten pages, with three orders left for the last. The number of pages is worked out from the list itself. The row only reports which page was asked for; showing that page's orders is the screen's work.
Press next, or a number where the numbers fit: the list goes to that page's orders, and the text under it says which orders are shown. Go to the last page: there are three orders there, and next cannot be pressed.
The list is five orders tall on every page: on the last page the two rows that have no order stand empty. Had the list grown shorter, the row under it would have moved up, out from under the finger that pressed it.
var page by rememberSaveable { mutableIntStateOf(1) }
val first = (page - 1) * ORDERS_PER_PAGE + 1
val last = minOf(page * ORDERS_PER_PAGE, ORDER_COUNT)
OrderRows(first = first, last = last, rows = ORDERS_PER_PAGE, tagKey = "order")
PantrixText(
text = "$first–$last of $ORDER_COUNT orders",
color = PantrixTheme.colors.textSecondary,
tagKey = "orders_shown"
)
PantrixPagination(
page = page,
pageCount = (ORDER_COUNT + ORDERS_PER_PAGE - 1) / ORDERS_PER_PAGE,
onPageChange = { page = it },
tagKey = "orders"
)
@Composable
private fun OrderRows(
first: Int,
last: Int,
rows: Int,
tagKey: String
) {
PantrixSurface(modifier = Modifier.fillMaxWidth(), border = PantrixTheme.colors.divider) {
Column {
for (order in first until first + rows) {
val listed = order <= last
// The line of an empty row keeps its place too, but is not drawn.
val line = if (listed) Color.Unspecified else Color.Transparent
if (order > first) PantrixHorizontalDivider(color = line)
Row(
modifier = Modifier.fillMaxWidth().padding(PantrixTheme.spacing.md),
horizontalArrangement = Arrangement.SpaceBetween
) {
if (listed) {
PantrixText(text = "Order #${FIRST_ORDER + order}", tagKey = "${tagKey}_$order")
PantrixText(text = "Items: ${1 + order % 4}", color = PantrixTheme.colors.textSecondary)
} else {
// An empty text is a line tall too; it has nothing to say to a screen reader.
PantrixText(text = "", role = TextRole.Decorative)
}
}
}
}
}
}
private const val ORDER_COUNT = 48
private const val ORDERS_PER_PAGE = 5
private const val FIRST_ORDER = 4800
How many pages beside the one on screen and at the ends
siblingCount says how many pages are shown on each side of the page on screen, and boundaryCount how many at each end of the row; each is one unless given. Four rows of twenty pages show the same page: press a page in one of them, and all four go there.
The first row is given neither. The second shows two pages on each side of the page on screen, and the third two pages at each end. In the last one both are zero: only the page on screen is left in the middle, and the others are reached by the arrows.
A row has as many items whichever page is on screen. Press 1 in the first row: at an end one of the gaps goes, and the pages at that end take its place; in the last row the second page stands beside the first.
The rows are in a frame that scrolls sideways: there the width has no end, and the rows keep their numbers on a narrow screen too.
var page by rememberSaveable { mutableIntStateOf(10) }
val secondary = PantrixTheme.colors.textSecondary
HorizontalScrollFrame(tagKey = "around") {
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
PantrixText(text = "Neither is given: one page on each side, one at each end", color = secondary)
PantrixPagination(page = page, pageCount = 20, onPageChange = { page = it }, tagKey = "around_usual")
PantrixText(text = "siblingCount = 2", color = secondary)
PantrixPagination(
page = page,
pageCount = 20,
onPageChange = { page = it },
siblingCount = 2,
tagKey = "around_siblings"
)
PantrixText(text = "boundaryCount = 2", color = secondary)
PantrixPagination(
page = page,
pageCount = 20,
onPageChange = { page = it },
boundaryCount = 2,
tagKey = "around_boundaries"
)
PantrixText(text = "siblingCount = 0, boundaryCount = 0", color = secondary)
PantrixPagination(
page = page,
pageCount = 20,
onPageChange = { page = it },
siblingCount = 0,
boundaryCount = 0,
tagKey = "around_none"
)
}
}
With buttons that go to the first and the last page
firstAndLast = true puts one more button outside previous and outside next: one goes to the first page, the other to the last. It is for going from one end to the other in one press, in a list of many pages such as an archive.
Press the last page button: the row goes to the fortieth page; there neither next nor the last page button can be pressed. The first page button goes to the first page, and there the two buttons at the start cannot be pressed. The page that was asked for is written on the card's "Last event" line.
Four buttons leave less room for the numbers: at the same width this row folds before one with two buttons does. On a phone held upright it is in its short form: two buttons, "Page 12 of 40" and two buttons. On the narrowest phones, where four buttons leave no room for the words, the end of the words is cut and the buttons are not.
val report = LocalExampleEvents.current
var page by rememberSaveable { mutableIntStateOf(12) }
PantrixPagination(
page = page,
pageCount = 40,
onPageChange = { asked ->
page = asked
report("Page $asked was asked for")
},
firstAndLast = true,
tagKey = "ends"
)
Where it is too narrow for the numbers
The same row at three widths: the first as wide as the example, the second in a frame of 320dp, the third in one of 240dp. The row fits its place step by step. The first frame is too narrow for the seven items of ten pages: there the row gives up the pages beside the page on screen, and stands with five items. In the second frame that does not fit either: the row is laid out as previous, "Page 3 of 10" and next. Nothing was given for this: the row looks at the width left to it, not at the window.
The three show the same page: press next in one of the frames, and all three go to that page. A row folds the same way on every page: none of them changes its layout as the page moves. Make the window narrower: the row at the top also shows fewer numbers first, and then goes to its short form.
The frames' widths were chosen for the 32dp items of desktop and the web. On a phone the items are larger, and the touch target is kept free around them: there both frames are too narrow for the numbers, and the short row stands in both. The row at the top, by the phone's width, either shows fewer numbers or is short too.
var page by rememberSaveable { mutableIntStateOf(3) }
PantrixPagination(page = page, pageCount = 10, onPageChange = { page = it }, tagKey = "roomy")
PantrixSurface(modifier = Modifier.width(320.dp), border = PantrixTheme.colors.divider) {
PantrixPagination(
page = page,
pageCount = 10,
onPageChange = { page = it },
modifier = Modifier.padding(horizontal = PantrixTheme.spacing.md),
tagKey = "fewer"
)
}
PantrixSurface(modifier = Modifier.width(240.dp), border = PantrixTheme.colors.divider) {
PantrixPagination(
page = page,
pageCount = 10,
onPageChange = { page = it },
modifier = Modifier.padding(horizontal = PantrixTheme.spacing.md),
tagKey = "narrow"
)
}
The short row at every width
PaginationStyle(layout = PaginationLayout.Compact) asks for the short row at every width: where the numbers would fit, too, the row is previous, the page's place and next. It is for a place where people step from page to page and do not jump to a number, such as the foot of a table.
Press next: the words become "Page 2 of 5"; a screen reader is told the changed words without being asked. Next cannot be pressed on the fifth page, nor previous on the first.
var page by rememberSaveable { mutableIntStateOf(1) }
PantrixPagination(
page = page,
pageCount = 5,
onPageChange = { page = it },
style = PaginationStyle(layout = PaginationLayout.Compact),
tagKey = "compact"
)
A row that cannot be pressed while the list loads
enabled = false turns the whole row off: the numbers, previous and next cannot be pressed, and the row is drawn in the theme's disabled colours. It is used so that a second page is not asked for while one is loading: enabled = !loading.
While the switch is on, the list counts as loading: press next or, where the numbers fit, a number; the card's "Last event" line does not change. Turn the switch off and press again: the page that was asked for is reported. The page on screen is told in a row that cannot be pressed too: by its fill in a row of numbers, by its words in the short row.
If the list starts loading while the keyboard is on a number or an arrow, the focus stays there: what it is on cannot be pressed, but once the list has come the keyboard goes on from where it was.
val report = LocalExampleEvents.current
var loading by rememberSaveable { mutableStateOf(true) }
var page by rememberSaveable { mutableIntStateOf(4) }
PantrixSwitchButton(
checked = loading,
onCheckedChange = { loading = it },
label = "The list is loading",
tagKey = "list_loading"
)
PantrixPagination(
page = page,
pageCount = 10,
onPageChange = { asked ->
page = asked
report("Page $asked was asked for")
},
enabled = !loading,
tagKey = "while_loading"
)
In a table's foot: page size and go to page
A table's foot: PantrixPageSize chooses how many orders a page shows, PantrixPagination moves between the pages, and PantrixPageJump goes to the page whose number is typed. The three are in a FlowRow: where there is room they stand side by side, and in a narrow place the one that does not fit goes down to the next line; on a phone held upright the three stand one under another. A Row does not take what does not fit down a line: it squeezes the last one into the room that is left. The three may not be the same height: itemVerticalAlignment lines them up by their middles.
All three read the screen's state, and none knows of the others. Change the page size: forty-eight orders make sixteen pages three at a time, and five pages ten at a time; the row's numbers and the number of digits the field takes follow the new number of pages. As the size changes the first order shown stays on screen: the page that is opened is the one that order falls on at the new size. On the fourth page, with orders 16–20 shown, choose 10: the second page comes, orders 11–20. For forty-eight orders the sizes are small: 3 and 5, before the first of the ready sizes (DefaultPageSizes), 10.
Type a number in the field and press Enter: that page is opened, the field is emptied and the focus stays in the field. A number larger than the last page opens the last page; the field takes nothing but digits. The page that was asked for, whatever asked for it, is written on the card's "Last event" line.
val report = LocalExampleEvents.current
var pageSize by rememberSaveable { mutableIntStateOf(ORDERS_PER_PAGE) }
var page by rememberSaveable { mutableIntStateOf(1) }
val pageCount = (ORDER_COUNT + pageSize - 1) / pageSize
val first = (page - 1) * pageSize + 1
val last = minOf(page * pageSize, ORDER_COUNT)
val open: (Int) -> Unit = { asked ->
page = asked
report("Page $asked was asked for")
}
OrderRows(first = first, last = last, rows = pageSize, tagKey = "row")
PantrixText(
text = "$first–$last of $ORDER_COUNT orders",
color = PantrixTheme.colors.textSecondary,
tagKey = "foot_shown"
)
FlowRow(
horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.lg),
verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
itemVerticalAlignment = Alignment.CenterVertically
) {
PantrixPageSize(
pageSize = pageSize,
onPageSizeChange = { size ->
// The page that is opened is the one the first order shown falls on at the new size: the order stays on screen.
val kept = (first - 1) / size + 1
pageSize = size
page = kept
report("$size orders to a page: page $kept was opened")
},
pageSizes = listOf(3, 5) + DefaultPageSizes.first(),
tagKey = "foot"
)
PantrixPagination(page = page, pageCount = pageCount, onPageChange = open, tagKey = "foot")
PantrixPageJump(pageCount = pageCount, onPageChange = open, tagKey = "foot")
}
@Composable
private fun OrderRows(
first: Int,
last: Int,
rows: Int,
tagKey: String
) {
PantrixSurface(modifier = Modifier.fillMaxWidth(), border = PantrixTheme.colors.divider) {
Column {
for (order in first until first + rows) {
val listed = order <= last
// The line of an empty row keeps its place too, but is not drawn.
val line = if (listed) Color.Unspecified else Color.Transparent
if (order > first) PantrixHorizontalDivider(color = line)
Row(
modifier = Modifier.fillMaxWidth().padding(PantrixTheme.spacing.md),
horizontalArrangement = Arrangement.SpaceBetween
) {
if (listed) {
PantrixText(text = "Order #${FIRST_ORDER + order}", tagKey = "${tagKey}_$order")
PantrixText(text = "Items: ${1 + order % 4}", color = PantrixTheme.colors.textSecondary)
} else {
// An empty text is a line tall too; it has nothing to say to a screen reader.
PantrixText(text = "", role = TextRole.Decorative)
}
}
}
}
}
}
private const val ORDER_COUNT = 48
private const val ORDERS_PER_PAGE = 5
private const val FIRST_ORDER = 4800
In Arabic: a row that starts on the right, and Arabic digits
The same row in an Arabic section: the inner theme is given locale alone, PantrixLocale.Arabic. The row starts on the right: previous is on the right, the arrows turn round, and the numbers grow towards the left. The numbers are written in Arabic digits: the language's pack carries its digits too (PantrixStrings.digits). The one below is the short row: its words are Arabic, and its numbers are written in the same digits.
Press a page: the card's "Last event" line writes the page that was asked for in the app's language. The digits change the writing alone: onPageChange reports the same number in every language. The names said to a screen reader are Arabic too, and are written in the same digits.
On a phone held upright the row at the top, by the phone's width, also shows fewer numbers or is short.
val report = LocalExampleEvents.current
var page by rememberSaveable { mutableIntStateOf(3) }
val open: (Int) -> Unit = { asked ->
page = asked
report("Page $asked was asked for")
}
PantrixTheme(locale = PantrixLocale.Arabic) {
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md)
) {
PantrixPagination(page = page, pageCount = 10, onPageChange = open, tagKey = "arabic")
PantrixPagination(
page = page,
pageCount = 10,
onPageChange = open,
style = PaginationStyle(layout = PaginationLayout.Compact),
tagKey = "arabic_short"
)
}
}
With its own colours, and on a fill
colors takes the colour of the numbers and of the short row's words (content), of previous, next and the gaps' marks (control), and of the fill and the number of the page on screen (selectedContainer, selectedContent) one by one; one that is left out stays the theme's. In the first row the arrows and the fill of the page on screen are in the app's own purple, which is in none of the theme's roles. The theme cannot know what reads on a fill it does not have: the colour of its number is given too. The other numbers are given no colour, and stay in the theme's text colour.
The second row is on a fill that is not one of the theme's grounds, and no colour is given: the fill says what is written on it, and all of the row is written in that colour. The page on screen is told by its fill, a share of the same colour.
val own = ownColors()
var page by rememberSaveable { mutableIntStateOf(2) }
PantrixPagination(
page = page,
pageCount = 3,
onPageChange = { page = it },
colors = PaginationColors(control = own.color, selectedContainer = own.color, selectedContent = own.onColor),
tagKey = "own"
)
PantrixSurface(
modifier = Modifier.fillMaxWidth(),
color = PantrixTheme.colors.primary.color,
shape = PantrixTheme.shapes.md
) {
PantrixPagination(
page = page,
pageCount = 3,
onPageChange = { page = it },
modifier = Modifier.padding(horizontal = PantrixTheme.spacing.md),
tagKey = "filled"
)
}
Sizes and shape
style gives the row's sizes; only the fields that are set change. itemSize is the size of a number, of previous and of next, itemShape their corners, and itemGap the room between two neighbours. The arrows' icon grows and shrinks with its item: it is 4dp more than half of it.
The middle row is as it is with nothing given. The one above it is built with 24dp items, fully round and with no room put between them; the one below it with 48dp items, medium corners and 8dp between them. The platform's touch target is kept free around the small items too: the items shrink, but come no closer to each other than that target.
A larger item is not written larger by itself: the bottom row is also given the theme's title style, with textStyle.
var page by rememberSaveable { mutableIntStateOf(2) }
PantrixPagination(
page = page,
pageCount = 3,
onPageChange = { page = it },
style = PaginationStyle(itemSize = 24.dp, itemShape = ShapeRole.Full, itemGap = 0.dp),
tagKey = "small"
)
PantrixPagination(page = page, pageCount = 3, onPageChange = { page = it }, tagKey = "usual")
PantrixPagination(
page = page,
pageCount = 3,
onPageChange = { page = it },
textStyle = PantrixTheme.typography.title,
style = PaginationStyle(itemSize = 48.dp, itemShape = ShapeRole.Medium, itemGap = 8.dp),
tagKey = "large"
)
API
page
Moves between the pages of a long list or a table.
| Parameter | Type | Default | What it is |
|---|---|---|---|
page | Int | the page on screen, counted from one, as it is written on the row: a pager's or a carousel's index counts from nought, and is this less one. A number outside the pages is taken as the nearest page. | |
pageCount | Int | how many pages there are. A list with nothing in it has one page, an empty one: a count under one is taken as one. | |
onPageChange | (page: Int) -> Unit | told the page that was asked for, by its number or by a button. The row shows it once page says so. | |
modifier | Modifier | Modifier | applied to the row. |
siblingCount | Int | 1 | in a row of numbers, how many pages are shown on each side of the page on screen where there is room for them: none or more. More than there are pages is all of them. |
boundaryCount | Int | 1 | in a row of numbers, how many pages are always shown at each end where there is room for them: none or more. |
firstAndLast | Boolean | false | whether the row has, outside previous and next, the two buttons that go to the first page and to the last. |
enabled | Boolean | true | whether the row can be pressed: one that cannot is drawn in the theme's disabled colours. |
textStyle | TextStyle | PantrixTheme.typography.label | the type the numbers and the words are set in: the theme's label unless given. An item that is made larger by the style is not written larger by itself. |
style | PaginationStyle? | null | this call's own style: over every enclosing one and under the density. Only the fields it sets change, on every platform. |
colors | PaginationColors? | null | this call's own colours. Only the ones it sets change; the rest stay the theme's. |
tagKey | String? | null | a locale-independent key for automation: the row's tag is Pagination_<tagKey>, and its parts are named inside it, Pagination_<tagKey>.Page_<number>, Pagination_<tagKey>.Step_previous, Pagination_<tagKey>.Step_next, Pagination_<tagKey>.Step_first, Pagination_<tagKey>.Step_last, and Pagination_<tagKey>.Text_position for the words of a row without numbers. |
PaginationStyle
PantrixPagination's layout and geometry.
| Parameter | Type | Default | What it is |
|---|---|---|---|
layout | PaginationLayout? | null | How the pages are laid out: by their numbers on every platform, in a row that has the room. |
itemSize | Dp | Dp.Unspecified | A page's number, previous and next: 40dp on Android, 36dp on iOS, 32dp on desktop and the web. A number too long for it makes its item wider. The icons in previous and next are half of it and 4dp. |
itemShape | ShapeSpec | ShapeSpec.Unspecified | The corners of an item, of its fill where it is the page on screen and of its ring: round on Android and iOS, small on desktop and the web. |
itemGap | Dp | Dp.Unspecified | Between two neighbours of the row. |
PaginationColors
What a PantrixPagination is painted with, for a row that does not take the theme's colours: a colour that is set is used, and one that is left out stays the theme's.
| Parameter | Type | Default | What it is |
|---|---|---|---|
content | Color | Color.Unspecified | The numbers of the pages that are not on screen, and the words of a row that has no room for numbers. The theme's textPrimary. |
control | Color | Color.Unspecified | Previous and next, and the marks that stand for the pages folded away. The theme's textSecondary. |
selectedContainer | Color | Color.Unspecified | The fill of the page on screen. The primary role's container. |
selectedContent | Color | Color.Unspecified | The number of the page on screen: what the theme pairs with selectedContainer, which is the primary role's onContainer on the fill the row has by itself. The theme has no pair for a fill that is none of its roles' and writes on it as on the row's own: give such a fill its number too. |
Accessibility
- Keyboard. The numbers and the arrows are each a stop for Tab; Enter and Space press them. The page on screen is a stop too, and keeps the focus a keyboard put on it: on a page opened by the keyboard the focus stays where it is. When the row comes to one of its ends, the page on screen takes the focus of the button that can no longer be pressed; in the short row the button on the other side takes it.
- Screen reader. A number is a button named by the page it opens: "Page 4". The page on screen is no button and offers the reader nothing to press: it is read with the state "Current page". The gaps are not read. The buttons that go to the first and the last page are named "First page" and "Last page". The short row's words are told to the reader each time they change. The row is a group named "Pagination". On iOS the group has no name: the reader there reads a group's name after what it holds.