Application toolbar
A sticky toolbar for an application view, with leading controls, a title, optional search, and trailing actions. Use SiteHeader for site branding, primary navigation, and mobile navigation collapse.
Default
With no named slots supplied, the default slot fills the title region.
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-top-bar/ui-top-bar.html"
>
<ui-top-bar> <strong>Title</strong> </ui-top-bar><script setup>
import { UiTopBar } from "@threadlabs/looma";
</script>
<template>
<UiTopBar> <strong>Title</strong> </UiTopBar>
</template>import { UiTopBar } from "@threadlabs/looma";
export default function Example() {
return <UiTopBar>{" "}<strong>Title</strong>{" "}</UiTopBar>;
}/** @jsxImportSource preact */
import { UiTopBar } from "@threadlabs/looma";
export default function Example() {
return <UiTopBar>{" "}<strong>Title</strong>{" "}</UiTopBar>;
}<script>
import { UiTopBar } from "@threadlabs/looma";
</script>
<UiTopBar> <strong>Title</strong> </UiTopBar>import { Component } from "@angular/core";
import { UiTopBar } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiTopBar],
template: `
<header
ui-top-bar
> <strong>Title</strong> </header>
`,
})
export default class Example {}leading, search, and actions slots
Each named slot adds its region around the default title without requiring internal wrapper markup.
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-top-bar/ui-top-bar.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-button/ui-button.html"
>
<ui-top-bar>
<ui-button
slot="leading"
size="sm"
>Back</ui-button>
<strong>Title</strong>
<ui-button
slot="search"
size="sm"
>Search</ui-button>
<ui-button
slot="actions"
size="sm"
>Save</ui-button>
</ui-top-bar><script setup>
import { UiButton, UiTopBar } from "@threadlabs/looma";
</script>
<template>
<UiTopBar>
<template #leading>
<UiButton
size="sm"
>Back</UiButton>
</template>
<strong>Title</strong>
<template #search>
<UiButton
size="sm"
>Search</UiButton>
</template>
<template #actions>
<UiButton
size="sm"
>Save</UiButton>
</template>
</UiTopBar>
</template>import { UiButton, UiTopBar } from "@threadlabs/looma";
export default function Example() {
return <UiTopBar
slots={{
leading: <UiButton
size="sm"
>Back</UiButton>,
search: <UiButton
size="sm"
>Search</UiButton>,
actions: <UiButton
size="sm"
>Save</UiButton>,
}}
>{" "}{" "}<strong>Title</strong>{" "}{" "}{" "}</UiTopBar>;
}/** @jsxImportSource preact */
import { UiButton, UiTopBar } from "@threadlabs/looma";
export default function Example() {
return <UiTopBar
slots={{
leading: <UiButton
size="sm"
>Back</UiButton>,
search: <UiButton
size="sm"
>Search</UiButton>,
actions: <UiButton
size="sm"
>Save</UiButton>,
}}
>{" "}{" "}<strong>Title</strong>{" "}{" "}{" "}</UiTopBar>;
}<script>
import { UiButton, UiTopBar } from "@threadlabs/looma";
</script>
{#snippet leading()}
<UiButton
size="sm"
>Back</UiButton>
{/snippet}
{#snippet search()}
<UiButton
size="sm"
>Search</UiButton>
{/snippet}
{#snippet actions()}
<UiButton
size="sm"
>Save</UiButton>
{/snippet}
<UiTopBar
slots={{ leading, search, actions }}
> <strong>Title</strong> </UiTopBar>import { Component } from "@angular/core";
import { UiButton, UiTopBar } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiTopBar, UiButton],
template: `
<header
ui-top-bar
>
<ng-container ngProjectAs="[slot='leading']">
<ng-template
ui-button
[size]="'sm'"
>Back</ng-template>
</ng-container>
<strong>Title</strong>
<ng-container ngProjectAs="[slot='search']">
<ng-template
ui-button
[size]="'sm'"
>Search</ng-template>
</ng-container>
<ng-container ngProjectAs="[slot='actions']">
<ng-template
ui-button
[size]="'sm'"
>Save</ng-template>
</ng-container>
</header>
`,
})
export default class Example {}Reveal the title after its heading
Scroll the document past its heading. The sticky title slides up and fades in once the heading leaves the visible reading area, and disappears when the heading returns. Reduced motion removes that transition.
A document with a long descriptive title
The heading labels the document while it is visible. Navigation and actions stay available.
Scroll to keep reading the document and its supporting notes.
The toolbar keeps the same height as the heading leaves the reading area.
Return to the beginning to show the full heading again.
The duplicate toolbar title is concealed while the heading is visible.
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-stack/ui-stack.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-scroll-area/ui-scroll-area.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-top-bar/ui-top-bar.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-button/ui-button.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-container/ui-container.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-text/ui-text.html"
>
<ui-stack
height="256"
gap="none"
>
<ui-scroll-area
fill
>
<ui-top-bar
title-for="top-bar-example-heading"
>
<ui-button
slot="leading"
size="sm"
>Back</ui-button>
A document with a long descriptive title
<ui-button
slot="actions"
size="sm"
>Save</ui-button>
</ui-top-bar>
<ui-container
fill
>
<ui-stack
gap="m"
>
<ui-text
as="h2"
variant="heading"
id="top-bar-example-heading"
>A document with a long descriptive title</ui-text>
<ui-text>The heading labels the document while it is visible. Navigation and actions stay available.</ui-text>
<ui-text>Scroll to keep reading the document and its supporting notes.</ui-text>
<ui-text>The toolbar keeps the same height as the heading leaves the reading area.</ui-text>
<ui-text>Return to the beginning to show the full heading again.</ui-text>
<ui-text>The duplicate toolbar title is concealed while the heading is visible.</ui-text>
</ui-stack>
</ui-container>
</ui-scroll-area>
</ui-stack><script setup>
import { UiButton, UiContainer, UiScrollArea, UiStack, UiText, UiTopBar } from "@threadlabs/looma";
</script>
<template>
<UiStack
:height="256"
gap="none"
>
<UiScrollArea
:fill="true"
>
<UiTopBar
title-for="top-bar-example-heading"
> <template #leading>
<UiButton
size="sm"
>Back</UiButton>
</template> A document with a long descriptive title <template #actions>
<UiButton
size="sm"
>Save</UiButton>
</template> </UiTopBar>
<UiContainer
:fill="true"
>
<UiStack
gap="m"
>
<UiText
as="h2"
variant="heading"
id="top-bar-example-heading"
>A document with a long descriptive title</UiText>
<UiText>The heading labels the document while it is visible. Navigation and actions stay available.</UiText>
<UiText>Scroll to keep reading the document and its supporting notes.</UiText>
<UiText>The toolbar keeps the same height as the heading leaves the reading area.</UiText>
<UiText>Return to the beginning to show the full heading again.</UiText>
<UiText>The duplicate toolbar title is concealed while the heading is visible.</UiText>
</UiStack>
</UiContainer>
</UiScrollArea>
</UiStack>
</template>import { UiButton, UiContainer, UiScrollArea, UiStack, UiText, UiTopBar } from "@threadlabs/looma";
export default function Example() {
return <UiStack
height={256}
gap="none"
>
<UiScrollArea
fill
>
<UiTopBar
titleFor="top-bar-example-heading"
slots={{
leading: <UiButton
size="sm"
>Back</UiButton>,
actions: <UiButton
size="sm"
>Save</UiButton>,
}}
>{" "}{" A document with a long descriptive title "}{" "}</UiTopBar>
<UiContainer
fill
>
<UiStack
gap="m"
>
<UiText
as="h2"
variant="heading"
id="top-bar-example-heading"
>A document with a long descriptive title</UiText>
<UiText>The heading labels the document while it is visible. Navigation and actions stay available.</UiText>
<UiText>Scroll to keep reading the document and its supporting notes.</UiText>
<UiText>The toolbar keeps the same height as the heading leaves the reading area.</UiText>
<UiText>Return to the beginning to show the full heading again.</UiText>
<UiText>The duplicate toolbar title is concealed while the heading is visible.</UiText>
</UiStack>
</UiContainer>
</UiScrollArea>
</UiStack>;
}/** @jsxImportSource preact */
import { UiButton, UiContainer, UiScrollArea, UiStack, UiText, UiTopBar } from "@threadlabs/looma";
export default function Example() {
return <UiStack
height={256}
gap="none"
>
<UiScrollArea
fill
>
<UiTopBar
titleFor="top-bar-example-heading"
slots={{
leading: <UiButton
size="sm"
>Back</UiButton>,
actions: <UiButton
size="sm"
>Save</UiButton>,
}}
>{" "}{" A document with a long descriptive title "}{" "}</UiTopBar>
<UiContainer
fill
>
<UiStack
gap="m"
>
<UiText
as="h2"
variant="heading"
id="top-bar-example-heading"
>A document with a long descriptive title</UiText>
<UiText>The heading labels the document while it is visible. Navigation and actions stay available.</UiText>
<UiText>Scroll to keep reading the document and its supporting notes.</UiText>
<UiText>The toolbar keeps the same height as the heading leaves the reading area.</UiText>
<UiText>Return to the beginning to show the full heading again.</UiText>
<UiText>The duplicate toolbar title is concealed while the heading is visible.</UiText>
</UiStack>
</UiContainer>
</UiScrollArea>
</UiStack>;
}<script>
import { UiButton, UiContainer, UiScrollArea, UiStack, UiText, UiTopBar } from "@threadlabs/looma";
</script>
{#snippet leading()}
<UiButton
size="sm"
>Back</UiButton>
{/snippet}
{#snippet actions()}
<UiButton
size="sm"
>Save</UiButton>
{/snippet}
<UiStack
height={256}
gap="none"
>
<UiScrollArea
fill
>
<UiTopBar
titleFor="top-bar-example-heading"
slots={{ leading, actions }}
> A document with a long descriptive title </UiTopBar>
<UiContainer
fill
>
<UiStack
gap="m"
>
<UiText
as="h2"
variant="heading"
id="top-bar-example-heading"
>A document with a long descriptive title</UiText>
<UiText>The heading labels the document while it is visible. Navigation and actions stay available.</UiText>
<UiText>Scroll to keep reading the document and its supporting notes.</UiText>
<UiText>The toolbar keeps the same height as the heading leaves the reading area.</UiText>
<UiText>Return to the beginning to show the full heading again.</UiText>
<UiText>The duplicate toolbar title is concealed while the heading is visible.</UiText>
</UiStack>
</UiContainer>
</UiScrollArea>
</UiStack>import { Component } from "@angular/core";
import { UiButton, UiContainer, UiScrollArea, UiStack, UiText, UiTopBar } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiStack, UiScrollArea, UiTopBar, UiButton, UiContainer, UiText],
template: `
<div
ui-stack
[height]="256"
[gap]="'none'"
>
<div
ui-scroll-area
[fill]="true"
>
<header
ui-top-bar
[titleFor]="'top-bar-example-heading'"
> <ng-container ngProjectAs="[slot='leading']">
<ng-template
ui-button
[size]="'sm'"
>Back</ng-template>
</ng-container> A document with a long descriptive title <ng-container ngProjectAs="[slot='actions']">
<ng-template
ui-button
[size]="'sm'"
>Save</ng-template>
</ng-container> </header>
<div
ui-container
[fill]="true"
>
<div
ui-stack
[gap]="'m'"
>
<ng-template
ui-text
[as]="'h2'"
[variant]="'heading'"
[hnAttributes]="{ id: 'top-bar-example-heading' }"
>A document with a long descriptive title</ng-template>
<ng-template
ui-text
>The heading labels the document while it is visible. Navigation and actions stay available.</ng-template>
<ng-template
ui-text
>Scroll to keep reading the document and its supporting notes.</ng-template>
<ng-template
ui-text
>The toolbar keeps the same height as the heading leaves the reading area.</ng-template>
<ng-template
ui-text
>Return to the beginning to show the full heading again.</ng-template>
<ng-template
ui-text
>The duplicate toolbar title is concealed while the heading is visible.</ng-template>
</div>
</div>
</div>
</div>
`,
})
export default class Example {}API
Package: @threadlabs/looma · Native root: header
Attributes
| Name | Description | Property | Type | Default | Allowed values |
|---|---|---|---|---|---|
title-for | The ID of the page heading represented by the default title slot. While that heading is visible below the sticky bar, its duplicate title is concealed. After the heading scrolls above the bar, the single-line title slides up and fades in. Leading and action slots stay available, and the bar keeps its size. Omit it for an always-visible title. Reduced motion removes the transition. | titleFor | string | | — |
Framework props
| Name | Type | Default | Allowed values |
|---|---|---|---|
titleFor | string | | — |
Events
No events.
Slots
| Name | Purpose |
|---|---|
leading | Named content for the leading region. |
default | Default child content. |
search | Named content for the search region. |
actions | Named content for the actions region. |
Design tokens
Set shared theme properties on a theme boundary. Component hooks apply only to their owning component.
Component tokens
| Token | Declared values | Fallback |
|---|---|---|
--ui-top-bar-actions-gap | — | var(--ui-space-1) |
--ui-top-bar-border | — | var(--ui-border-divider) |
--ui-top-bar-gap | — | var(--ui-space-3) |
--ui-top-bar-height | — | 56px |
--ui-top-bar-padding-inline | — | var(--ui-space-4) |
--ui-top-bar-surface | — | var(--ui-surface-elevated) |
--ui-top-bar-z-index | — | 100 |
Shared tokens
| Token | Fallback |
|---|---|
--ui-border-divider | — |
--ui-border-width | — |
--ui-motion-ease | — |
--ui-motion-fast | — |
--ui-space-1 | — |
--ui-space-2 | — |
--ui-space-3 | — |
--ui-space-4 | — |
--ui-surface-elevated | — |