Layout

Footer

A site's footer: brand and tagline, columns of links under titles, and a bottom line with the small print.

#layout#page#navigation#link#no-js

Demo

Preview

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.qwe
main.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>}
Thread
66Useful? Like it, or add to its thread below.

Thread 0 posts

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

No posts yet. The first one opens the thread.