App bar

The bar across the top of a screen, holding the screen's name and its most important actions. It sticks to the top as the page scrolls.

Usage

The headline prop is called headline. An optional subtitle sits under it, and the bar grows to fit rather than clipping.

Headline
Subtitle
<script lang="ts">
	import { AppBar, IconButton } from 'noph-ui'
	import { Icon } from 'noph-ui/icons'
</script>

<div style="width:26rem;max-width:100%;border-radius:1rem;overflow:hidden">
	<AppBar headline="Headline" subtitle="Subtitle">
		{#snippet leading()}
			<IconButton title="Back"><Icon>arrow_back</Icon></IconButton>
		{/snippet}
		{#snippet trailing()}
			<IconButton title="Search"><Icon>search</Icon></IconButton>
			<IconButton title="Choose date"><Icon>calendar_today</Icon></IconButton>
		{/snippet}
	</AppBar>
</div>

Variants

search carries a search field instead of a headline, as an emphasised, global entry point to search; put the field in the search snippet. small is one row tall. medium and large put the headline on a second line below the actions, giving the screen's name more weight.

Headline
small
Headline
medium
Headline
large
<script lang="ts">
	import { AppBar, IconButton, Search } from 'noph-ui'
	import { Icon } from 'noph-ui/icons'
	import Item from '#lib/list/Item.svelte'

	const dishes = ['Simple Classic Tacos', 'Mexican street corn', 'Chilaquiles verdes']

	let query = $state('')

	const matches = (q: string) =>
		q ? dishes.filter((d) => d.toLowerCase().includes(q.toLowerCase())) : dishes
</script>

<div style="display:grid;gap:1rem;width:26rem;max-width:100%">
	<div style="border-radius:1rem">
		<AppBar variant="search">
			{#snippet leading()}
				<IconButton title="Open navigation"><Icon>menu</Icon></IconButton>
			{/snippet}
			{#snippet search()}
				<Search bind:value={query} placeholder="Search product">
					{#each matches(query) as dish (dish)}
						<Item variant="button">{dish}</Item>
					{/each}
				</Search>
			{/snippet}
		</AppBar>
	</div>
	{#each ['small', 'medium', 'large'] as const as variant (variant)}
		<div style="border-radius:1rem;overflow:hidden">
			<AppBar {variant} headline="Headline" subtitle={variant}>
				{#snippet leading()}
					<IconButton title="Back"><Icon>arrow_back</Icon></IconButton>
				{/snippet}
				{#snippet trailing()}
					<IconButton title="Search"><Icon>search</Icon></IconButton>
					<IconButton title="Choose date"><Icon>calendar_today</Icon></IconButton>
				{/snippet}
			</AppBar>
		</div>
	{/each}
</div>

Collapsing

collapsible shrinks a medium or large bar down to one row as the page scrolls, moving the headline up into the action row. It is driven by animation-timeline: scroll(), so there is no scroll listener and no state to keep. In a browser without scroll-driven animations the bar simply stays expanded.

By default it follows the page scroller. If the bar sits inside its own scroll container, pass scroller="nearest" and make the bar a direct child of that container.

A collapsing bar also needs scroll anchoring off on whichever element scrolls, otherwise the browser compensates for the shrinking bar by pushing the scroll position back and the bar never collapses. The component sets overflow-anchor: none on the scroller for you, so there is nothing to add.

Headline
Subtitle

Row 1

Row 2

Row 3

Row 4

Row 5

Row 6

Row 7

Row 8

Row 9

Row 10

Row 11

Row 12

Row 13

Row 14

Row 15

Row 16

Row 17

Row 18

Row 19

Row 20

<script lang="ts">
	import { AppBar, IconButton } from 'noph-ui'
	import { Icon } from 'noph-ui/icons'
</script>

<div
	style="width:26rem;max-width:100%;height:20rem;overflow:auto;border-radius:1rem;background:var(--np-color-surface-container-low)"
>
	<AppBar variant="large" collapsible scroller="nearest" headline="Headline" subtitle="Subtitle">
		{#snippet leading()}
			<IconButton title="Open navigation"><Icon>menu</Icon></IconButton>
		{/snippet}
	</AppBar>
	<div style="padding:1rem;display:grid;gap:1rem">
		{#each Array.from({ length: 20 }, (_, i) => i) as row (row)}
			<p style="margin:0">Row {row + 1}</p>
		{/each}
	</div>
</div>

Theming

Custom propertyDescription
--np-app-bar-container-colorBackground of the bar.
--np-app-bar-headline-colorHeadline text color.

API

AppBar attributes

Renders a <header> and takes its attributes. bind:element gives you that element.

AttributeTypeDefaultDescription
headlinestring | undefinedundefinedThe screen's name.
subtitlestring | undefinedundefinedSecondary line under the headline.
variant'search' | 'small' | 'medium' | 'large''small'One row, or two with the headline below.
searchSnippet | undefinedundefinedThe search field, for variant="search". Replaces the headline, which a search app bar does not show.
leadingSnippet | undefinedundefinedLeading action, usually a navigation or back icon button.
trailingSnippet | undefinedundefinedTrailing actions.
collapsiblebooleanfalseCollapses a medium or large bar to one row on scroll. Ignored by the one-row variants, which have nothing to collapse.
scroller'root' | 'nearest''root'Which scroller the collapse follows.