Layout

PageHeader

A page's top: breadcrumb, title, a line about it, small facts and the actions, with room under it for tabs.

#layout#page#navigation#no-js

Demo

Preview

Orders

Everything bought this month, newest first.

All customers
Customer

Ada Lovelace

ActiveSince March 202412 orders

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

Example

The code of the preview above.

demos/page_header.qwe
view PageHeaderDemo() =    <div.demo-stack style="gap: 32px">        <PageHeader title="Orders" description="Everything bought this month, newest first."                    breadcrumb={<Breadcrumbs items={[{ label: "Home", href: "#" }, { label: "Shop", href: "#" }, { label: "Orders" }]}/>}                    actions={[<Button variant="outline" id="page-header-demo-export">Export</Button>, <Button>New order</Button>]}>            <Tabs>                <Tab group="page-header-demo-tabs" label="All" selected={true}></Tab>                <Tab group="page-header-demo-tabs" label="Open"></Tab>                <Tab group="page-header-demo-tabs" label="Shipped"></Tab>            </Tabs>        </PageHeader>        <PageHeader title="Ada Lovelace" eyebrow="Customer" back="#page_header" back_label="All customers"                    avatar={<Avatar name="Ada Lovelace" size="lg"/>}                    meta={[<Badge tone="success">Active</Badge>, <span>Since March 2024</span>, <span>12 orders</span>]}                    actions={<Button variant="outline" size="sm">Edit</Button>} divider={false}/>    </div>

Source

ui/page_header.qwe
// PageHeader: the top of a page: where it sits (a breadcrumb), its title, a line// about it, and what can be done to it (buttons), in one row that wraps on phones.////   <PageHeader title="Orders" description="Everything bought this month."//               breadcrumb={<Breadcrumbs items={[{ label: "Home", href: "/" }, { label: "Orders" }]}/>}//               actions={[<Button variant="outline">Export</Button>, <Button>New order</Button>]}/>//   <PageHeader title="Ada Lovelace" eyebrow="Customer" avatar={<Avatar name="Ada Lovelace"/>}//               meta={<Badge tone="success">Active</Badge>} back="/customers">//       <Tabs> ... </Tabs>//   </PageHeader>//// title: the page's <h1>. eyebrow: a small line above it (a category, a section).// description: a line under it. meta: HTML under the description (small facts: a// Badge, a date, a count). avatar: HTML before the title (an Avatar, an icon).// breadcrumb: HTML above the title (a Breadcrumbs). back: an href for a "Back" link// above the title instead, with back_label as its text ("Back").// actions: HTML at the right end of the row (buttons); on a phone they go under.// children: below the row (tabs, a filter bar). divider: a line along its bottom (true).import ui/theme.qwe use ui_clslet page_header_css = css`.ui-pagehead { display: grid; gap: 12px; padding-bottom: 20px; color: var(--ui-fg); font: 15px/1.5 var(--ui-font); }.ui-pagehead-line { border-bottom: 1px solid var(--ui-border); }.ui-pagehead-back {  display: inline-flex; align-items: center; gap: 4px; width: fit-content; color: var(--ui-muted); font-size: 14px;  text-decoration: none; border-radius: var(--ui-radius-sm);}.ui-pagehead-back:hover { color: var(--ui-fg); }.ui-pagehead-back:focus-visible { outline: none; box-shadow: var(--ui-focus); }.ui-pagehead-back svg { width: 16px; height: 16px; }.ui-pagehead-row { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 12px 24px; }.ui-pagehead-main { display: flex; flex: 1 1 320px; align-items: flex-start; gap: 14px; min-width: 0; }.ui-pagehead-avatar { flex: none; padding-top: 2px; }.ui-pagehead-text { display: grid; gap: 4px; min-width: 0; }.ui-pagehead-eyebrow { color: var(--ui-muted); font-size: 12px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }.ui-pagehead-title { margin: 0; font-size: 26px; font-weight: 650; line-height: 1.2; letter-spacing: -.01em; overflow-wrap: anywhere; }.ui-pagehead-desc { max-width: 64ch; margin: 0; color: var(--ui-muted); }.ui-pagehead-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; margin-top: 4px; color: var(--ui-muted); font-size: 14px; }.ui-pagehead-actions { display: flex; flex: none; flex-wrap: wrap; align-items: center; gap: 8px; margin-left: auto; }.ui-pagehead-below:empty { display: none; }.ui-pagehead-below > :first-child { margin-top: 0; }@media (max-width: 599px) { .ui-pagehead-title { font-size: 22px; } .ui-pagehead-actions { width: 100%; margin-left: 0; } }`view PageHeader(title: str, eyebrow: str? = null, description: str? = null, meta = null, avatar = null,                breadcrumb = null, back: str? = null, back_label: str = "Back", actions = null, divider: bool = true,                class: str? = null, children) {    style global page_header_css    <header class={ui_cls(["ui-pagehead", divider && "ui-pagehead-line", class])}>        {breadcrumb != null            ? <div.ui-pagehead-crumb>{breadcrumb}</div>            : back != null && <a.ui-pagehead-back href={back}>                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"                     stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6"/></svg>                {back_label}            </a>}        <div.ui-pagehead-row>            <div.ui-pagehead-main>                {avatar != null && <div.ui-pagehead-avatar>{avatar}</div>}                <div.ui-pagehead-text>                    {eyebrow != null && <span.ui-pagehead-eyebrow>{eyebrow}</span>}                    <h1.ui-pagehead-title>{title}</h1>                    {description != null && <p.ui-pagehead-desc>{description}</p>}                    {meta != null && <div.ui-pagehead-meta>{meta}</div>}                </div>            </div>            {actions != null && <div.ui-pagehead-actions>{actions}</div>}        </div>        <div.ui-pagehead-below>{children}</div>    </header>}
Thread
75Useful? Like it, or add to its thread below.

Thread 0 posts

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

No posts yet. The first one opens the thread.