App Bar
Top application bar: a header landmark that reports scroll elevation and can hide while scrolling down.
| Package | @vizejs/ui/app-bar |
| Maturity | stable |
| Own the source | vize lib pull app-bar |
| Requires | — |
| Aliases | top app bar, app header, navigation bar, header bar |
| Covers | HTML header landmark, Material top app bar, Vuetify v-app-bar |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/ui
Add the public import below to <script setup lang="ts">. Components provide behavior without styles; the preview uses optional Paper styles.
import { AppBar } from "@vizejs/ui/app-bar";
Or copy the source into your project with vize lib pull app-bar (see Source Distribution).
Try it
This is the basic example maintained with the component source, using the public package imports. The preview adds the optional Paper styles.
Open the interactive example · Styling these components
Copy the example
<!-- Top app bar with a menu button, a title, and a search action that hides while scrolling down. -->
<script setup lang="ts">
import { useId } from "vue";
import { AppBar } from "@vizejs/ui/app-bar";
const titleId = useId();
</script>
<template>
<AppBar hide-on-scroll :aria-labelledby="titleId">
<template #start>
<button type="button" aria-label="Open navigation">≡</button>
</template>
<template #default="{ elevated }">
<span :id="titleId" :data-elevated="elevated ? 'true' : undefined">Inbox</span>
</template>
<template #end>
<button type="button">Search</button>
</template>
</AppBar>
</template>
API
AppBar
Source: src/families/navigation/app-bar/app-bar.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
as |
"header" | "div" |
"header" |
Host element. A top-level header is the page's banner landmark; use div when the bar sits inside another landmark that already has a header. |
target |
AppBarTarget |
null |
Scroll container to follow: an element, a selector, or null for the window. |
elevateThreshold |
number |
0 |
Scroll offset in CSS pixels past which the bar reports elevated. |
hideOnScroll |
boolean |
false |
Report hidden while the container scrolls down, and visible again as soon as it scrolls up. |
hideThreshold |
number |
64 |
Scroll offset in CSS pixels before hideOnScroll may hide the bar. |
ariaLabel |
string |
undefined |
Accessible name of the landmark when no visible title labels it. |
ariaLabelledby |
string |
undefined |
Ids that label the landmark (overrides ariaLabel). |
Events
| Event | Payload | Description |
|---|---|---|
visibilityChange |
[hidden: boolean] |
Fired when hideOnScroll hides or reveals the bar. |
Slots
| Slot | Slot props | Description |
|---|---|---|
start |
AppBarSlotState |
Leading content such as a navigation or back button. |
default |
AppBarSlotState |
Title and main content. |
end |
AppBarSlotState |
Trailing actions. |
Exposed
| Member | Type | Description |
|---|---|---|
elevated |
boolean |
Whether the followed container has scrolled past elevateThreshold. |
hidden |
boolean |
Whether hideOnScroll currently asks the consumer to move the bar out of view. |
state |
AppBarState |
Stable visibility token for styling and tests. |
scrollTop |
number |
Current scroll offset of the followed container in CSS pixels. |
element |
HTMLElement | null |
Rendered root element. |
show |
() => void |
Bring a hidden bar back into view. |
refresh |
() => number |
Re-read the scroll offset, for containers that scroll without a scroll event. |
Behavior
Normative state x input -> outcome table for app-bar.vue (@vizejs/ui/app-bar). An app bar
is the page's top bar: a header landmark with leading, main, and trailing content. It only
reports scroll state (data-elevated, data-hidden, data-state); positioning, elevation, and
the hide transition stay consumer-owned CSS. Every row is proven by the named test in
app-bar.test.ts or app-bar-ssr.test.ts.
| # | State | Input | Outcome | Proven by |
|---|---|---|---|---|
| AB1 | render | slots / as / labels |
<header> (or <div>) with start, content, end parts; empty start/end render nothing; ARIA labels apply |
renders a header landmark with start, content, and end parts |
| AB2 | window scroll | offset past elevateThreshold |
data-elevated="true" strictly past the threshold, removed at or below it; never hides without hideOnScroll |
reports elevation once the window scrolls past the threshold |
| AB3 | hideOnScroll |
scroll down / up | hides after hideThreshold while scrolling down, reveals on any upward scroll, emits visibilityChange each time |
hideOnScroll hides while scrolling down past the threshold and reveals on scroll up |
| AB4 | hidden | focus inside / show() |
focus reveals the bar and keeps it visible until focus leaves; show() reveals it |
focus inside a hidden bar reveals it and keeps it visible |
| AB5 | element target |
selector container scroll | follows the selected container and ignores window scrolling; refresh() re-reads the offset |
follows an element scroll container given as a selector |
| AB6 | option changes | hideOnScroll off / NaN |
turning hideOnScroll off reveals the bar; non-finite thresholds fall back to their defaults |
turning hideOnScroll off reveals a hidden bar, and invalid thresholds fall back |
| AB7 | SSR / hydration | isolated requests | byte-identical visible markup without scroll state, hydrating without diagnostics | renders byte-identical app bar markup and hydrates without mismatches |
Hiding only publishes state: the bar keeps its content in the DOM and in the tab order, and
keyboard focus brings it back, so a consumer's off-screen transform never traps focus out of
view. Use as="div" when the bar sits inside a landmark that already has a header.