Actions

LoadMoreButton

The button at the end of a list that says how many are left, spins while loading, and says when there are none.

#button#list#loading#no-js

Demo

Preview
  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5

That's all

Get it

It needs theme.qwe, as every component does; or take the whole kit, quillo-ui.qwe. Each component brings its own styles to the pages that show it.

$ curl -O https://quillolang.org/components/ui/theme.qwe$ curl -O https://quillolang.org/components/ui/load_more_button.qwe
main.qwe
import ui/theme.qwe use theme_cssuse ui/load_more_button.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>

Example

The code of the preview above.

demos/load_more_button.qwe
// A load from the server, slowed a little so that the spinner shows.server fn load_more_button_demo_wait() with time = sleep(400)component LoadMoreButtonDemoLive() {    state shown = 5    state busy = false    let total = 17    <div.demo-stack>        <ul style="margin: 0; padding-left: 20px; columns: 2">            {for i in range(1, shown + 1) => <li key={i}>Item {i}</li>}        </ul>        <LoadMoreButton id="load-more-demo-live" remaining={total - shown} batch={6} loading={busy}                        on_click={() => {                            busy = true                            load_more_button_demo_wait()                            shown = min([total, shown + 6])                            busy = false                        }}/>    </div>}view LoadMoreButtonDemo() =    <div.demo-stack>        <LoadMoreButtonDemoLive/>        <div.demo-row>            <LoadMoreButton id="load-more-demo-link" remaining={24} href="#load_more_button"/>            <LoadMoreButton loading={true} variant="soft"/>            <LoadMoreButton label="Show older" variant="ghost" size="sm"/>            <LoadMoreButton remaining={0}/>        </div>    </div>

Source

ui/load_more_button.qwe
// LoadMoreButton: the button at the end of a list that fetches the next batch,// saying how many are left ("Load more · 24 left"), showing a spinner while they// come, and "That's all" once there are none. As a link (href) it works without// JavaScript, to the next page.////   <LoadMoreButton remaining={24} href="/posts?page=3"/>//   <LoadMoreButton remaining={left} loading={busy} on_click={() => { more() }}/>//// remaining: how many are not shown yet; 0 shows `done` instead of the button, and// null leaves the count out. batch: how many the next load brings, said as "Show 20// more". loading: a spinner, "Loading…", and the button disabled.// label ("Load more"), loading_label ("Loading…"), done ("That's all"): the texts.// href makes it a link; else on_click(), inside one of your components.// variant: "outline" (default), "soft", "ghost" or "solid"; size: "sm", "md" or "lg";// full: as wide as its container. It is styled as a Button when button_css is on the// page, and is a status region, so screen readers hear the count change.import ui/theme.qwe use ui_clslet load_more_button_css = css`.ui-load-more-button { display: flex; flex-direction: column; align-items: center; gap: 8px; }.ui-load-more-button .ui-btn { gap: 8px; }.ui-load-more-button-count { opacity: .7; font-weight: 400; }.ui-load-more-button-count::before { content: "·"; margin-right: 8px; }.ui-load-more-button-done { margin: 0; color: var(--ui-muted); font: 14px/1.4 var(--ui-font); }`view LoadMoreButton(remaining: int? = null, batch: int? = null, loading: bool = false, label: str = "Load more",                    loading_label: str = "Loading…", done: str = "That's all", href: str? = null, variant: str = "outline",                    size: str = "md", full: bool = false, on_click = null, id: str? = null, class: str? = null) {    style global load_more_button_css    let cls = ui_cls(["ui-btn", `ui-btn-${variant}`, size != "md" && `ui-btn-${size}`, full && "ui-btn-full"])    let text = batch != null && remaining != null ? `Show ${min([batch, remaining])} more` : label    let count = remaining != null && batch == null ? `${remaining} left` : batch != null && remaining != null && remaining > batch ? `of ${remaining}` : null    let body = [        loading && <span.ui-btn-spin aria-hidden="true"></span>,        <span>{loading ? loading_label : text}</span>,        !loading && count != null && <span.ui-load-more-button-count>{count}</span>,    ]    <div class={ui_cls(["ui-load-more-button", class])} id={id} role="status" aria-live="polite">        {remaining == 0            ? <p.ui-load-more-button-done>{done}</p>            : href != null && !loading                ? <a class={cls} href={href}>{body}</a>                : <button class={cls} type="button" disabled={loading} aria-busy={loading ? "true" : null}                          @click={() => { on_click && on_click() }}>{body}</button>}    </div>}
Thread
57Useful? Like it, or add to its thread below.

Thread 0 posts

On LoadMoreButton: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.