Footer
A site's footer: brand and tagline, columns of links under titles, and a bottom line with the small print.
Demo
Below, in a 400px-wide box, the columns wrap and the social links take a line of their own.
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/footer.qwemain.qwe
import ui/theme.qwe use theme_cssuse ui/footer.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
demos/footer.qwe
let footer_demo_columns = [ { title: "Product", links: [{ label: "Pricing", href: "#" }, { label: "Changelog", href: "#" }, { label: "Roadmap", href: "#" }] }, { title: "Company", links: [{ label: "About", href: "#" }, { label: "Jobs", href: "#" }, { label: "Press", href: "#" }] }, { title: "Help", links: [{ label: "Docs", href: "#" }, { label: "Status", href: "#" }, { label: "Contact", href: "#" }] }]view FooterDemo() = <div.demo-stack> <Footer id="footer-demo-site" brand="Acme" brand_href="#footer" tagline="Tools for small teams who ship often." columns={footer_demo_columns} bottom="© 2026 Acme Ltd. All rights reserved." tone="subtle" links={[{ label: "Privacy", href: "#" }, { label: "Terms", href: "#" }, { label: "Cookies", href: "#" }]}> <a href="#" aria-label="Acme on GitHub" style="color: var(--ui-muted)">GitHub</a> <a href="#" aria-label="Acme on Mastodon" style="color: var(--ui-muted)">Mastodon</a> </Footer> <p.demo-note>Below, in a 400px-wide box, the columns wrap and the social links take a line of their own.</p> <div style="width: 400px; max-width: 100%"> <Footer id="footer-demo-narrow" brand="Acme" columns={footer_demo_columns} bottom="© 2026 Acme Ltd."> <a href="#" style="color: var(--ui-muted)">GitHub</a> </Footer> </div> </div>Source
ui/footer.qwe
// Footer: the bottom of a site: its name and a line about it, columns of links// under titles, and a last line with the copyright, the small print and room for// social links. The columns wrap when it is narrow.//// <Footer brand="Acme" tagline="Tools for small teams." bottom="© 2026 Acme Ltd."// columns={[{ title: "Product", links: [{ label: "Pricing", href: "/pricing" }, { label: "Changelog", href: "/changelog" }] },// { title: "Company", links: [{ label: "About", href: "/about" }, { label: "Jobs", href: "/jobs" }] }]}// links={[{ label: "Privacy", href: "/privacy" }, { label: "Terms", href: "/terms" }]}>// <SocialLinks .../>// </Footer>//// brand, brand_href ("/"): the site's name, a link home. logo: HTML before the name.// tagline: a line under the name. columns: a list of { title, links: [{ label, href }] },// each a <nav> named by its title. bottom: the last line's text (a copyright).// links: small links on the last line ({ label, href }). children: HTML at the end of// the last line (social links, a language picker).// tone: "plain" (default) or "subtle" (a tinted band). label: what screen readers// call the whole footer ("Footer").import ui/theme.qwe use ui_clslet footer_css = css`.ui-footer { container: ui-footer / inline-size; color: var(--ui-fg); font: 14px/1.5 var(--ui-font); border-top: 1px solid var(--ui-border); }.ui-footer-subtle { background: var(--ui-subtle); }.ui-footer-in { max-width: 1140px; margin-inline: auto; padding: 40px 24px 24px; }.ui-footer-top { display: flex; flex-wrap: wrap; gap: 32px 48px; }.ui-footer-brand { flex: 1 1 220px; max-width: 320px; }.ui-footer-name { display: inline-flex; align-items: center; gap: 8px; color: var(--ui-fg); font-size: 17px; font-weight: 650; text-decoration: none; border-radius: var(--ui-radius-sm); }.ui-footer-name :is(img, svg) { height: 24px; width: auto; }.ui-footer-tagline { margin: 8px 0 0; color: var(--ui-muted); }.ui-footer-cols { display: flex; flex: 2 1 420px; flex-wrap: wrap; gap: 24px 40px; }.ui-footer-col { flex: 1 1 120px; min-width: 0; }.ui-footer-col h3 { margin: 0 0 10px; font-size: 13px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--ui-fg); }.ui-footer-col ul, .ui-footer-links { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; }.ui-footer a { color: var(--ui-muted); text-decoration: none; border-radius: var(--ui-radius-sm); }.ui-footer a:hover { color: var(--ui-fg); text-decoration: underline; }.ui-footer a:focus-visible { outline: none; box-shadow: var(--ui-focus); }.ui-footer-bottom { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 20px; margin-top: 32px; padding-top: 18px; border-top: 1px solid var(--ui-border); color: var(--ui-muted); font-size: 13px;}.ui-footer-bottom p { margin: 0; }.ui-footer-links { display: flex; flex-wrap: wrap; gap: 4px 16px; }.ui-footer-end { display: flex; align-items: center; gap: 10px; margin-left: auto; }.ui-footer-end:empty { display: none; }@container ui-footer (max-width: 640px) { .ui-footer-in { padding: 32px 16px 20px; } .ui-footer-cols { gap: 20px 24px; } .ui-footer-end { margin-left: 0; width: 100%; }}`view Footer(brand: str? = null, brand_href: str = "/", logo = null, tagline: str? = null, columns: list = [], bottom: str? = null, links: list = [], tone: str = "plain", label: str = "Footer", id: str? = null, class: str? = null, children) { style global footer_css <footer class={ui_cls(["ui-footer", tone == "subtle" && "ui-footer-subtle", class])} id={id} aria-label={label}> <div.ui-footer-in> {(brand != null || logo != null || len(columns) > 0) && <div.ui-footer-top> {(brand != null || logo != null) && <div.ui-footer-brand> <a.ui-footer-name href={brand_href}>{logo}{brand}</a> {tagline != null && <p.ui-footer-tagline>{tagline}</p>} </div>} {len(columns) > 0 && <div.ui-footer-cols> {for c in columns => <nav.ui-footer-col aria-label={c.title}> <h3>{c.title}</h3> <ul>{for l in c.links => <li><a href={l.href}>{l.label}</a></li>}</ul> </nav>} </div>} </div>} <div.ui-footer-bottom> {bottom != null && <p>{bottom}</p>} {len(links) > 0 && <ul.ui-footer-links>{for l in links => <li><a href={l.href}>{l.label}</a></li>}</ul>} <div.ui-footer-end>{children}</div> </div> </div> </footer>}Related
AppShellAn app's frame: a sidebar of links, a top bar and the page; the sidebar is a drawer on phones.10 views · 8 downloadsPageHeaderA page's top: breadcrumb, title, a line about it, small facts and the actions, with room under it for tabs.7 views · 5 downloadsSidebarLayoutContent beside a sidebar, left or right, that goes under the content where its box is narrow.5 views · 6 downloadsCollapsibleA block shown and hidden under a line you click, on the browser's own <details>; open by default or not.7 views · 6 downloadsCoverA block as tall as the screen with one thing in its middle, and something at its top and bottom if given.7 views · 7 downloadsDockA floating bar of icon buttons fixed to the bottom or a side of the page, with badges and the current one marked.6 views · 7 downloads
Thread
Thread 0 posts
On Footer: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.