limn
    ↑↓ ChooseEnter OpenEsc Close
    GitHub

    Components/Navigation

    Pagination

    Numbered pages between a previous and a next arrow. Use it under a list or a table that is shown one page at a time, where a reader may want to jump to a page as well as step to the next.

    Native componentGuide source

    Preview

    CodeSource
    fn view(state: &State, palette: ComponentPalette) -> Element {
        Pagination::new("results", state.page, state.pages, palette).render()
    }
    
    fn update(state: &mut State, action: &UiAction) {
        if let UiAction::Clicked { id } = action {
            if let Some(page) = Pagination::page_of(id, "results") {
                state.page = page;
            }
        }
    }

    Examples

    Each one is the library drawing it. Press, type and hover.

    Siblings1 / 2
    CodeSource
    pagination(cx, "pagination-none", "Pages, no siblings", 40).siblings(0).render()
    Siblings2 / 2
    CodeSource
    pagination(cx, "pagination-two", "Pages, two siblings", 40).siblings(2).render()
    Compact
    CodeSource
    pagination(cx, "pagination-compact", "Results pages, compact", 12).compact().render()
    Sizes1 / 4
    CodeSource

    Read the source of this example.

    Sizes2 / 4
    CodeSource

    Read the source of this example.

    Sizes3 / 4
    CodeSource

    Read the source of this example.

    Sizes4 / 4
    CodeSource

    Read the source of this example.

    Disabled1 / 2
    CodeSource
    pagination(cx, "pagination-off", "Results pages, disabled", 12).disabled().render()
    Disabled2 / 2
    CodeSource
    pagination(cx, "pagination-off-compact", "Results pages, compact and disabled", 12).compact().disabled().render()
    Edge cases1 / 4
    CodeSource
    pagination(cx, "pagination-few", "Seven pages", 7).render()
    Edge cases2 / 4
    CodeSource
    pagination(cx, "pagination-one", "One page", 1).render()
    Edge cases3 / 4
    CodeSource
    pagination(cx, "pagination-empty", "No pages", 0).render()
    Edge cases4 / 4
    CodeSource
    pagination(cx, "pagination-long", "Two thousand pages", 2000).render()

    Pagination

    Numbered pages between a previous and a next arrow. Use it under a list or a table that is shown one page at a time, where a reader may want to jump to a page as well as step to the next.

    Import

    use limn::{Component, ControlSize, Pagination};

    Usage

    A pagination is controlled: pass the current page and the number of pages each frame, and store the page a button reports. Pages count from 1.

    fn view(state: &State, palette: ComponentPalette) -> Element {
        Pagination::new("results", state.page, state.pages, palette).render()
    }
    
    fn update(state: &mut State, action: &UiAction) {
        if let UiAction::Clicked { id } = action {
            if let Some(page) = Pagination::page_of(id, "results") {
                state.page = page;
            }
        }
    }

    Every button reports UiAction::Clicked with {id}={page}: results=4 for the number 4, and for the previous arrow on page 5. Pagination::page_of(action_id, id) reads the page back. It is None for an action that is not from this row, so it can be tried on every click. The current page is a button too and reports its own page.

    A page below 1 is read as the first page, and one past the end as the last.

    Which pages show

    Pagination::new("results", 6, 40, palette).siblings(2).render()

    The first and the last page always show. Between them stand the current page and siblings pages on each side of it, 1 unless set, and an ellipsis where pages are left out: 1 … 4 5 6 … 12. An ellipsis is three muted dots, not a button.

    The row has 2 * siblings + 5 cells between its arrows whatever the current page. Near an end the cells an ellipsis would not need hold more numbers instead: page 1 of 12 is 1 2 3 4 5 … 12. So a button stays under the pointer while the reader clicks through. With no more pages than cells, every page shows and there is no ellipsis.

    Each number’s cell is as wide as the row is high, and wider for all of them when the last page has more digits than fit, so the row is the same width on every page. The width is worked out from the number of digits, not measured.

    Compact

    Pagination::new("results", state.page, state.pages, palette).compact().render()

    compact() shows the two arrows around the position as text, “3 / 12”, in place of the numbers. The text sits in a slot wide enough for the last page, so the arrows do not move.

    Sizes

    Pagination::new("results", state.page, state.pages, palette).size(ControlSize::Dense).render()
    SizeHeight of the arrows and the numbers
    ControlSize::Dense24
    ControlSize::Compact28
    ControlSize::Regular, the default32
    ControlSize::Spacious36

    The ends and an empty list

    On the first page the previous arrow is disabled, and on the last the next one: it keeps its place and its hint, and takes no pointer or focus.

    With one page both arrows are disabled around the number 1. With no pages the row is the two disabled arrows alone, around “0 / 0” if it is compact, so the place under an empty list does not collapse. Leave the row out if you would rather show nothing.

    Labels

    Pagination::new("resultados", state.page, state.pages, palette)
        .labels("Página anterior", "Página siguiente", "Página")
        .render()

    labels(previous, next, page) gives the words of the row: the hint and name of each arrow, and the word a number is named with for a screen reader, said before the number. They are “Previous page”, “Next page” and “Page” unless set.

    Disabled

    Pagination::new("results", state.page, state.pages, palette).disabled().render()
    Pagination::new("results", state.page, state.pages, palette).enabled(!state.loading).render()

    A disabled row keeps every cell in its place, in the muted color, with the current page still marked by a fill. It takes no pointer or focus and reports nothing.

    Pagination or Pager

    UseWhen
    PaginationThe sequence is numbered pages and the reader may jump to one. It owns the arithmetic: which pages show, which ends can be taken, what each button reports.
    Pagination with compact()The same pages in a narrow place: previous, “3 / 12”, next.
    PagerThe position is not a page number, or the label is yours to write: “change 2 of 5”, a file name, search matches. The host writes the label, gives each arrow its own action ID and says which ends can be taken. It is 24 high and can point up and down.

    Keyboard

    KeyEffect
    Tab, Shift+TabMove through the arrows and the numbers that can be taken, in order.
    Enter, SpaceReport the page of the focused button.

    A number keeps the focus when it becomes the current page, so Enter can be followed by Tab to the next one.

    Motion

    The hover and press fills of each button fade over tokens().motion.hover_ms.

    Actions

    ActionWhen
    UiAction::Clicked { id } with {id}={page}A number is activated, with its own page; the previous arrow, with the page before the current one; the next arrow, with the page after it.

    Accessibility

    Each number is a button named “Page 4”, and the current one is told as the selected one. The arrows are buttons named by their hints, “Previous page” and “Next page”. A button that cannot be taken, at an end or in a disabled row, is still there and says it is disabled.

    Pagination::new("results", state.page, state.pages, palette).accessibility_label("Results pages")

    With accessibility_label the row is a group of that name, known by the row’s ID, around its buttons. In compact form the position is plain text between the arrows.

    API reference

    The guide covers composition, options and actions. Generate the complete Rust type and builder reference from the checkout:

    cargo doc -p limn --open

    Component API overview · State and actions

    The example is drawn by crates/limn-gallery/src/pages/pagination.rs.