App bar
On this page
An app bar is a <header> with a row inside it. The pieces are separate so you can arrange them: appBarNav() for links, appBarSpacer() to push what follows to the far end, and appBarActions() for the buttons at the end.
Basic app bar
appBar({ brand: 'sitelo' },
appBarSpacer(),
appBarActions(
button({ size: 'sm', variant: 'soft' }, 'Sign in'),
),
)With navigation
navLink() is the link style for a bar; current marks the active page with aria-current as well as colour.
appBar({ brand: 'sitelo' },
appBarNav(
navLink({ href: '#docs', current: true }, 'Docs'),
navLink({ href: '#ui' }, 'UI'),
navLink({ href: '#examples' }, 'Examples'),
),
appBarSpacer(),
appBarActions(
button({ size: 'sm', variant: 'outline', color: 'neutral' }, 'GitHub'),
button({ size: 'sm' }, 'Get started'),
),
)A brand with a mark
The brand takes any markup, and links to / unless href says otherwise.
appBar({
href: '#home',
brand: stack({ direction: 'row', gap: 'sm', inline: true, align: 'center' },
avatar({ name: 'S', size: 'sm', square: true, color: 'primary' }),
'sitelo',
),
},
appBarSpacer(),
appBarActions(chip({ size: 'sm', color: 'neutral' }, 'v2.6.3')),
)Sticky and blurred
sticky pins the bar to the top of the scroll container; blur makes it translucent so content passes under it. Both are shown here inside a scrolling box rather than on the page itself.
Scroll me — paragraph 1.
Scroll me — paragraph 2.
Scroll me — paragraph 3.
Scroll me — paragraph 4.
Scroll me — paragraph 5.
Scroll me — paragraph 6.
div({ style: 'height: 12rem; overflow: auto; border: 1px solid var(--su-border); border-radius: 0.6rem' },
appBar({ brand: 'sitelo', sticky: true, blur: true },
appBarSpacer(),
appBarActions(chip({ size: 'sm', color: 'primary' }, 'sticky')),
),
container({ size: 'sm', style: 'padding-block: 1rem' },
stack({ gap: 'md' },
...Array.from({ length: 6 }, (unused, index) =>
text({ variant: 'small', tone: 'muted' }, 'Scroll me — paragraph ' + (index + 1) + '.'),
),
),
),
)Out of the way while scrolling
sticky: 'auto' keeps the bar pinned, but slides it away while the page scrolls down and brings it back as soon as it scrolls up, or reaches the top. It stays in view while keyboard focus is inside it, or a menu in it is open.
In Chromium this is all CSS, @container scroll-state(scrolled), and nothing is fetched. Other browsers fetch a small module when the page loads, which watches the scroll instead. The bar follows the page; inside a scrolling box of your own, like the one here, give the box container-type: scroll-state as well.
Scroll down, then back up — paragraph 1.
Scroll down, then back up — paragraph 2.
Scroll down, then back up — paragraph 3.
Scroll down, then back up — paragraph 4.
Scroll down, then back up — paragraph 5.
Scroll down, then back up — paragraph 6.
Scroll down, then back up — paragraph 7.
Scroll down, then back up — paragraph 8.
Scroll down, then back up — paragraph 9.
Scroll down, then back up — paragraph 10.
Scroll down, then back up — paragraph 11.
Scroll down, then back up — paragraph 12.
div({ style: 'height: 12rem; overflow: auto; container-type: scroll-state; border: 1px solid var(--su-border); border-radius: 0.6rem' },
appBar({ brand: 'sitelo', sticky: 'auto', blur: true },
appBarSpacer(),
appBarActions(chip({ size: 'sm', color: 'primary' }, 'auto')),
),
container({ size: 'sm', style: 'padding-block: 1rem' },
stack({ gap: 'md' },
...Array.from({ length: 12 }, (unused, index) =>
text({ variant: 'small', tone: 'muted' }, 'Scroll down, then back up — paragraph ' + (index + 1) + '.'),
),
),
),
)With a drawer on small screens
The usual pattern: links in the bar on desktop, a button that opens a drawer() on a phone. The drawer is a <dialog> the button opens with a command, so it needs no script.
fragment(
appBar({ brand: 'sitelo' },
appBarSpacer(),
appBarActions(
themeToggle(),
iconButton({
label: 'Open navigation',
variant: 'ghost',
color: 'neutral',
commandfor: 'app-bar-drawer', command: 'show-modal',
icon: icon('menu'),
}),
),
),
drawer({ id: 'app-bar-drawer', title: 'Navigation' },
navLink({ href: '#docs' }, 'Docs'),
navLink({ href: '#ui' }, 'UI'),
navLink({ href: '#examples' }, 'Examples'),
),
)Props
appBar():
| Prop | Type | Default | Description |
|---|---|---|---|
brand | Child | — | Content of the brand link at the start. |
href | string | '/' | Where the brand links to. |
sticky | boolean | 'auto' | false | Pins the bar to the top on scroll. 'auto' also hides it while scrolling down. |
blur | boolean | false | Translucent background with a backdrop blur. |
as | string | 'header' | Element to render. |
The pieces:
| Piece | Props | Default | Description |
|---|---|---|---|
appBarNav | — | A nav element holding the links. | |
appBarSpacer | — | Flexible gap; everything after it goes to the far end. | |
appBarActions | — | Trailing cluster of buttons. | |
navLink | href, current, color | — | A link styled for the bar; current marks the active page. |