Navigation

JumpLinks

A row of links to the sections of the page, scrolling sideways when narrow and sticking to the top if asked.

#navigation#link#page#no-js

Demo

Preview

Overview: the section the link goes to.

Specs: the section the link goes to.

Reviews: the section the link goes to.

Questions: the section the link goes to.

Similar items: the section the link goes to.

Narrow, the row scrolls sideways.

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/jump_links.qwe
main.qwe
import ui/theme.qwe use theme_cssuse ui/jump_links.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>

Example

The code of the preview above.

demos/jump_links.qwe
let jump_links_demo_items = [    { id: "jump-demo-overview", label: "Overview" }, { id: "jump-demo-specs", label: "Specs" },    { id: "jump-demo-reviews", label: "Reviews", badge: 128 }, { id: "jump-demo-qa", label: "Questions", badge: 12 },    { id: "jump-demo-similar", label: "Similar items" }, { href: "#jump_links", label: "Back to top" }]view JumpLinksDemo() =    <div.demo-stack style="gap: 20px">        <JumpLinks id="jump-links-demo" title="Jump to" items={jump_links_demo_items} current="jump-demo-specs"/>        <div style="display: grid; gap: 8px">            {for it in jump_links_demo_items | filter((it) => get(it, "id") != null) =>                <p.demo-note id={it.id} style="margin: 0">{it.label}: the section the link goes to.</p>}        </div>        <JumpLinks id="jump-links-demo-underline" variant="underline" items={jump_links_demo_items} current="jump-demo-reviews"/>        <div style="width: 320px; border: 1px solid var(--ui-border); border-radius: var(--ui-radius); padding: 0 8px">            <JumpLinks id="jump-links-demo-narrow" items={jump_links_demo_items}/>        </div>        <p.demo-note>Narrow, the row scrolls sideways.</p>    </div>

Source

ui/jump_links.qwe
// JumpLinks: a row of links to the sections of the page, across the top of a long// one (a product page, a profile, a settings page). It scrolls sideways when there// is no room, and can stick to the top as the page scrolls. The links go to ids on// the page, so they need no script; Scrollspy is the one that follows the scrolling.////   <JumpLinks items={[{ id: "overview", label: "Overview" }, { id: "specs", label: "Specs" },//                      { id: "reviews", label: "Reviews", badge: 128 }]}/>//// items: { id, label, badge? } (id: the section's id), or { href, label } for a link// elsewhere. current: the id (or href) of the link marked (aria-current="location").// sticky: it stays at the top as the page scrolls (top: var(--ui-jump-top, 0)).// title: a short word at the left ("Jump to"). label: what screen readers call it// ("On this page"). variant: "pill" (default) or "underline".import ui/theme.qwe use ui_clslet jump_links_css = css`.ui-jump {  display: flex; align-items: center; gap: 10px; min-width: 0; background: var(--ui-bg); color: var(--ui-fg);  font: 14px/1.4 var(--ui-font);}.ui-jump-sticky { position: sticky; top: var(--ui-jump-top, 0); z-index: 5; border-bottom: 1px solid var(--ui-border); }.ui-jump-title { flex: none; color: var(--ui-muted); font-size: 13px; font-weight: 500; }.ui-jump ul {  display: flex; flex: 1; gap: 4px; min-width: 0; margin: 0; padding: 4px 0; list-style: none; overflow-x: auto;  scrollbar-width: none; scroll-snap-type: x proximity;}.ui-jump ul::-webkit-scrollbar { display: none; }.ui-jump li { scroll-snap-align: start; }.ui-jump-link {  display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 12px; border-radius: 999px;  color: var(--ui-muted); font-weight: 500; text-decoration: none; white-space: nowrap; transition: color .12s, background .12s;}.ui-jump-link:hover { color: var(--ui-fg); background: var(--ui-subtle); }.ui-jump-link:focus-visible { outline: none; box-shadow: var(--ui-focus); }.ui-jump-link[aria-current] { color: var(--ui-accent); background: var(--ui-accent-soft); }.ui-jump-badge { color: var(--ui-muted); font-size: 12px; font-variant-numeric: tabular-nums; }.ui-jump-link[aria-current] .ui-jump-badge { color: inherit; opacity: .8; }.ui-jump-underline ul { gap: 0; padding: 0; }.ui-jump-underline .ui-jump-link { height: 42px; border-radius: 0; padding: 0 12px; box-shadow: inset 0 -2px 0 transparent; }.ui-jump-underline .ui-jump-link:hover { background: transparent; }.ui-jump-underline .ui-jump-link[aria-current] { background: transparent; color: var(--ui-fg); box-shadow: inset 0 -2px 0 var(--ui-accent); }@media (prefers-reduced-motion: reduce) { .ui-jump-link { transition: none; } }`view JumpLinks(items: list = [], current: str? = null, sticky: bool = false, title: str? = null, label: str = "On this page",               variant: str = "pill", id: str? = null, class: str? = null) {    style global jump_links_css    <nav class={ui_cls(["ui-jump", sticky && "ui-jump-sticky", variant == "underline" && "ui-jump-underline", class])} id={id}         aria-label={label}>        {title != null && <span.ui-jump-title>{title}</span>}        <ul>            {for it in items => {                let to = get(it, "href") ?? `#${it.id}`                let key = get(it, "id") ?? it.href                <li><a.ui-jump-link href={to} aria-current={current != null && current == key ? "location" : null}>                    <span>{it.label}</span>                    {get(it, "badge") != null && <span.ui-jump-badge>{it.badge}</span>}                </a></li>            }}        </ul>    </nav>}
Thread
66Useful? Like it, or add to its thread below.

Thread 0 posts

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

No posts yet. The first one opens the thread.