Tabs and progress dots

leptosbook ships FolioTabs for a labeled tab strip, and it's easy to hand-roll progress dots. Both follow the same idea: read current_page from context, and jump with go_to.

FolioTabs, wired to a folio

FolioTabs is intentionally decoupled from context — you pass it active and on_select. That makes it reusable outside a folio, but inside one you wire it up in three lines:

#![allow(unused)]
fn main() {
use std::sync::Arc;
use leptos::prelude::*;
use leptosbook::prelude::*;

#[component]
fn SectionTabs() -> impl IntoView {
    let ctx = use_folio_context();
    let go_to = ctx.go_to.clone();
    let on_select: Arc<dyn Fn(usize) + Send + Sync> = Arc::new(move |i| go_to(i));

    view! {
        <FolioTabs
            tabs=vec!["Overview", "Details", "Pricing"]
            active=ctx.current_page
            on_select=on_select
        />
    }
}
}

tabs is a Vec<&'static str>, so the labels are fixed at compile time — ideal for a known set of sections.

Hand-rolled progress dots

When you just want minimal dots that scale to any length, render straight from the context:

#![allow(unused)]
fn main() {
#[component]
fn Dots() -> impl IntoView {
    let ctx = use_folio_context();
    let go_to = ctx.go_to.clone();

    view! {
        <div class="dots">
            {move || {
                let cur = ctx.current_page.get();
                let go_to = go_to.clone();
                (0..ctx.total_pages.get()).map(move |i| {
                    let go_to = go_to.clone();
                    view! {
                        <button
                            class:on=move || i == cur
                            on:click=move |_| go_to(i)
                            aria-label=format!("Go to item {}", i + 1)
                        />
                    }
                }).collect_view()
            }}
        </div>
    }
}
}
.dots { display: flex; gap: .5rem; justify-content: center; padding: 1rem; }
.dots button {
  width: .6rem; height: .6rem; border-radius: 50%;
  border: none; background: rgba(255,255,255,.3); cursor: pointer;
  transition: background .2s, transform .2s;
}
.dots button.on { background: white; transform: scale(1.3); }

Which to use?

  • FolioTabs — a few, named sections (Overview / Details / Pricing).
  • Hand-rolled dots — many, unnamed items (a 12-photo gallery), or when you want full control over the markup and ARIA.