Skip to content

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.

Component

vue
<template>
	<div class="header">
		<Button
			class="header__menu-button"
			icon="fal fa-bars"
			severity="secondary"
			@click="openNav" />
		<h2>{{ title }}</h2>
		<slot />
	</div>
</template>

<script setup lang="ts">
import Button from 'primevue/button'
import { useNavigationStore } from '@/stores/Navigation'

defineProps<{
	title: string
}>()

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;
	align-items: center;
	gap: 16px;
	padding: 10px 16px;
	height: 64px;
	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.

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.

Dark Mode Support

The header automatically adapts to dark mode preferences using the @media (prefers-color-scheme: dark) media query. In dark mode:

  • Background changes to var(--p-surface-950)
  • Border color changes to var(--p-surface-900)

Layout

The header uses flexbox layout with:

  • align-items: center for vertical centering
  • gap: 16px for spacing between elements
  • The title (<h2>) has flex: 1 to take up available space
  • Fixed height of 64px

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'" />
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import Header from '@/components/Header.vue'

const route = useRoute()
const isEdit = computed(() => route.name === 'posts-edit')
</script>