Appearance
Header
Header is a component that provides a standardized header bar for views. It displays a title, includes a mobile navigation menu button, and provides a slot for action buttons. The component is sticky and provides consistent styling across all views.
- See also
Component
vue
<template>
<div class="header">
<div class="header__content">
<Button
class="header__menu-button"
icon="fal fa-bars"
severity="secondary"
@click="openNav" />
<h2>{{ title }}</h2>
<slot />
</div>
<HeaderLoader
class="header__loader"
:is-loading="isLoading" />
</div>
</template>
<script setup lang="ts">
import Button from 'primevue/button'
import { useNavigationStore } from '@/stores/Navigation'
import HeaderLoader from '@/components/HeaderLoader.vue'
defineProps<{
title: string
isLoading?: boolean
}>()
const navigation = useNavigationStore()
function openNav() {
if (window.matchMedia('(max-width: 1500px)').matches) {
navigation.open()
}
}
</script>
<style scoped lang="scss">
.header {
background: var(--p-surface-0);
position: sticky;
top: 0;
z-index: 1000;
border-left: 0;
border-top: 0;
border-right: 0;
border-bottom: 1px solid var(--p-surface-200);
display: flex;
flex-direction: column;
height: 64px;
.header__content {
display: flex;
align-items: center;
gap: 16px;
padding: 10px 16px;
height: 100%;
width: 100%;
}
min-height: 64px;
max-height: 64px;
width: 100%;
@media (prefers-color-scheme: dark) {
background: var(--p-surface-950);
border-bottom-color: var(--p-surface-900);
}
.header__menu-button {
display: none;
}
@media (max-width: 1500px) {
.header__menu-button {
display: inline-flex;
}
}
h2 {
font-size: 22px;
flex: 1;
}
}
</style>Props
title
- Type:
string - Required:
true - Description: The title text to display in the header. This is rendered as an
<h2>element and takes up the available flex space.
isLoading
- Type:
boolean - Required:
false - Description: Controls whether the integrated loading indicator is visible. When
true, a progress bar appears at the bottom of the header. Whenfalseorundefined, the loader is hidden. The loader includes a 100ms delay before appearing to prevent flicker for fast operations.
Slots
default
- Description: The default slot allows you to place action buttons or other content in the header. This is commonly used for "Create" buttons in list views. The slot content appears after the title, aligned to the right side of the header.
Behavior
Sticky Positioning
The header is positioned as sticky at the top of the viewport (top: 0). This means it remains visible when scrolling the page content. The header has a z-index of 1000 to ensure it appears above other content.
Mobile Menu Button
The header includes a hamburger menu button (fal fa-bars icon) that is hidden by default on larger screens. On screens with a maximum width of 1500px, the button becomes visible.
When clicked, the button opens the navigation overlay by calling navigation.open() from the NavigationStore. This only happens on screens smaller than 1500px, matching the breakpoint where the navigation becomes an overlay.
Usage Examples
List View
vue
<template>
<Header title="Posts">
<Button
icon="fal fa-plus"
label="Create"
@click="router.push({ name: 'posts-create' })" />
</Header>
</template>
<script setup lang="ts">
import Header from '@/components/Header.vue'
import Button from 'primevue/button'
import { useRouter } from 'vue-router'
const router = useRouter()
</script>Edit View
vue
<template>
<Header
:title="isEdit ? 'Edit Post' : 'Create Post'"
:is-loading="loaders.size > 0" />
<Container class="edit">
<Form
:id="route.params.id as string"
@start-loading="loaders.add('form')"
@stop-loading="loaders.delete('form')" />
</Container>
</template>
<script setup lang="ts">
import { reactive, computed } from 'vue'
import { useRoute } from 'vue-router'
import Header from '@/components/Header.vue'
import Container from '@/components/Container.vue'
import Form from './components/Form.vue'
const route = useRoute()
const isEdit = computed(() => route.name === 'posts-edit')
const loaders = reactive(new Set<string>())
</script>