Navigation

Subnav

A second row of links under the main navigation, for one section's pages, with counts and the current one marked.

#navigation#link#tabs#no-js

Demo

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

Example

The code of the preview above.

demos/subnav.qwe
let subnav_demo_links = [    { label: "Code", href: "#code", icon: "M8 6 2 12l6 6M16 6l6 6-6 6" },    { label: "Issues", href: "#subnav", icon: "M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18zM12 8v4M12 16h.01", badge: 24 },    { label: "Pull requests", href: "#pulls", badge: 3 },    { label: "Actions", href: "#actions" },    { label: "Wiki", href: "#wiki" },    { label: "Settings", href: "#settings" }]view SubnavDemo() =    <div.demo-stack style="gap: 20px">        <div style="border: 1px solid var(--ui-border); border-radius: var(--ui-radius); overflow: hidden">            <Subnav id="subnav-demo" title="quillo/components" links={subnav_demo_links} current="#subnav">                <Button size="sm" variant="outline" href="#subnav">Watch</Button>            </Subnav>            <div style="height: 32px"></div>        </div>        <Subnav id="subnav-demo-pill" variant="pill" label="Period" current="#month" links={[            { label: "Today", href: "#today" }, { label: "This week", href: "#week" },            { label: "This month", href: "#month" }, { label: "This year", href: "#year" }        ]}/>        <div style="width: 300px; border: 1px solid var(--ui-border); border-radius: var(--ui-radius); overflow: hidden">            <Subnav id="subnav-demo-narrow" links={subnav_demo_links} current="#wiki"/>        </div>        <p.demo-note>Narrow, the row scrolls sideways.</p>    </div>

Source

ui/subnav.qwe
// Subnav: a second row of links under a site's main navigation, for the pages of one// section (a product's Overview, Features, Pricing; a project's Code, Issues, Pull// requests). The current page is marked, and the row scrolls sideways when narrow.////   <Subnav title="Settings" current={request.path} links={[//       { label: "General", href: "/settings" },//       { label: "Members", href: "/settings/members", badge: 12 },//       { label: "Billing", href: "/settings/billing" }//   ]}/>//// links: { label, href, badge?, icon? }; the one whose href is `current` is marked// aria-current="page". badge: a count after the label. icon: a character or an emoji,// or an SVG path (24x24, stroked) when it starts with "M". title: a short heading at// the left of the row (a section's name). children: HTML at the right end (a button,// a search). label: what screen readers call it ("Section"). variant: "underline"// (default: a line under the current link, as a row of tabs) or "pill".import ui/theme.qwe use ui_clslet subnav_css = css`.ui-subnav {  display: flex; align-items: center; gap: 16px; border-bottom: 1px solid var(--ui-border); background: var(--ui-bg);  color: var(--ui-fg); font: 14px/1.4 var(--ui-font);}.ui-subnav-title { flex: none; padding: 0 0 0 4px; font-weight: 650; }.ui-subnav ul {  display: flex; flex: 1; gap: 2px; min-width: 0; margin: 0; padding: 0; list-style: none; overflow-x: auto;  scrollbar-width: none; -webkit-overflow-scrolling: touch;}.ui-subnav ul::-webkit-scrollbar { display: none; }.ui-subnav-link {  display: inline-flex; align-items: center; gap: 7px; height: 42px; padding: 0 10px; border-radius: var(--ui-radius-sm) var(--ui-radius-sm) 0 0;  color: var(--ui-muted); font-weight: 500; text-decoration: none; white-space: nowrap; box-shadow: inset 0 -2px 0 transparent;  transition: color .12s, background .12s, box-shadow .12s;}.ui-subnav-link:hover { color: var(--ui-fg); background: var(--ui-subtle); }.ui-subnav-link:focus-visible { outline: none; box-shadow: inset 0 -2px 0 transparent, var(--ui-focus); }.ui-subnav-link[aria-current="page"] { color: var(--ui-fg); box-shadow: inset 0 -2px 0 var(--ui-accent); }.ui-subnav-icon { display: inline-grid; place-items: center; width: 16px; height: 16px; font-size: 14px; line-height: 1; }.ui-subnav-icon svg { width: 16px; height: 16px; }.ui-subnav-badge {  min-width: 20px; padding: 1px 6px; border-radius: 999px; background: var(--ui-subtle); border: 1px solid var(--ui-border);  color: var(--ui-muted); font-size: 12px; font-weight: 600; text-align: center; font-variant-numeric: tabular-nums;}.ui-subnav-link[aria-current="page"] .ui-subnav-badge { color: var(--ui-fg); }.ui-subnav-end { display: flex; flex: none; align-items: center; gap: 8px; padding-right: 4px; }.ui-subnav-pill { border-bottom: 0; padding: 6px 0; }.ui-subnav-pill ul { gap: 4px; }.ui-subnav-pill .ui-subnav-link { height: 32px; border-radius: 999px; box-shadow: none; }.ui-subnav-pill .ui-subnav-link:focus-visible { box-shadow: var(--ui-focus); }.ui-subnav-pill .ui-subnav-link[aria-current="page"] { background: var(--ui-accent-soft); color: var(--ui-accent); box-shadow: none; }@media (prefers-reduced-motion: reduce) { .ui-subnav-link { transition: none; } }`view Subnav(links: list = [], current: str? = null, title: str? = null, label: str = "Section", variant: str = "underline",            id: str? = null, class: str? = null, children) {    style global subnav_css    <nav class={ui_cls(["ui-subnav", variant == "pill" && "ui-subnav-pill", class])} id={id} aria-label={label}>        {title != null && <span.ui-subnav-title>{title}</span>}        <ul>            {for l in links => <li>                <a.ui-subnav-link href={l.href} aria-current={current != null && l.href == current ? "page" : null}>                    {get(l, "icon") != null && <span.ui-subnav-icon aria-hidden="true">{starts_with(l.icon, "M") && len(l.icon) > 2                        ? <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"                               stroke-linejoin="round"><path d={l.icon}/></svg>                        : l.icon}</span>}                    <span>{l.label}</span>                    {get(l, "badge") != null && <span.ui-subnav-badge>{l.badge}</span>}                </a>            </li>}        </ul>        {children != null && <div.ui-subnav-end>{children}</div>}    </nav>}
Thread
55Useful? Like it, or add to its thread below.

Thread 0 posts

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

No posts yet. The first one opens the thread.