Header

GitHub
A responsive header for your site navigation.

Usage

The Header component renders a <header> element.

Its height is defined through a --ui-header-height CSS variable.

Use the left, default and right slots to customize the header and the body or content slots to customize the header menu.

<script setup lang="ts">
import type { NavigationMenuItem } from 'pohon-ui'

const route = useRoute()

const items = computed<Array<NavigationMenuItem>>(() => [
  {
    label: 'Docs',
    to: '/pohon/getting-started',
    active: route.path.startsWith('/pohon/getting-started')
  },
  {
    label: 'Components',
    to: '/pohon/components',
    active: route.path.startsWith('/pohon/components')
  },
  {
    label: 'Theme',
    to: '/theme',
    target: '_blank'
  },
  {
    label: 'Releases',
    to: 'https://github.com/vinicunca/pohon/releases',
    target: '_blank'
  }
])
</script>

<template>
  <PHeader>
    <template #title>
      <Logo class="h-6 w-auto" />
    </template>

    <PNavigationMenu :items="items" />

    <template #right>
      <PColorModeButton />

      <PTooltip text="Open on GitHub" :kbds="['meta', 'G']">
        <PButton
          color="neutral"
          variant="ghost"
          to="https://github.com/vinicunca/pohon"
          target="_blank"
          icon="i-simple-icons-github"
          aria-label="GitHub"
        />
      </PTooltip>
    </template>
  </PHeader>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type { NavigationMenuItem } from 'pohon-ui'

const route = useRoute()

const items = computed<Array<NavigationMenuItem>>(() => [
  {
    label: 'Docs',
    to: '/pohon/getting-started',
    active: route.path.startsWith('/pohon/getting-started')
  },
  {
    label: 'Components',
    to: '/pohon/components',
    active: route.path.startsWith('/pohon/components')
  },
  {
    label: 'Theme',
    to: '/theme',
    target: '_blank'
  },
  {
    label: 'Releases',
    to: 'https://github.com/vinicunca/pohon/releases',
    target: '_blank'
  }
])
</script>

<template>
  <PHeader>
    <template #title>
      <Logo class="h-6 w-auto" />
    </template>

    <PNavigationMenu :items="items" />

    <template #right>
      <PColorModeButton />

      <PTooltip text="Open on GitHub" :kbds="['meta', 'G']">
        <PButton
          color="neutral"
          variant="ghost"
          to="https://github.com/vinicunca/pohon"
          target="_blank"
          icon="i-simple-icons-github"
          aria-label="GitHub"
        />
      </PTooltip>
    </template>
  </PHeader>
</template>
In this example, we use the NavigationMenu component to render the header links in the center.

Title

Use the title prop to change the title of the header. Defaults to Pohon UI.

<template>
  <PHeader title="Pohon UI" />
</template>

You can also use the title slot to add your own logo.

You should still add the title prop to replace the default aria-label of the link.
<template>
  <PHeader>
    <template #title>
      <Logo class="h-6 w-auto" />
    </template>
  </PHeader>
</template>

To

Use the to prop to change the link of the title. Defaults to /.

<template>
  <PHeader to="/pohon/getting-started" />
</template>

You can also use the left slot to override the link entirely.

<template>
  <PHeader>
    <template #left>
      <NuxtLink to="/pohon/getting-started">
        <Logo class="h-6 w-auto" />
      </NuxtLink>
    </template>
  </PHeader>
</template>

Mode

Use the mode prop to change the mode of the header menu. Defaults to modal.

Use the body slot to fill the menu body (under the header) or the content slot to fill the entire menu.

You can use the menu prop to customize the menu of the header, it will adapt depending on the mode you choose.
<script setup lang="ts">
import type { NavigationMenuItem } from 'pohon-ui';

const route = useRoute();

const items = computed<Array<NavigationMenuItem>>(() => [{
  label: 'Docs',
  to: '/pohon/getting-started',
  icon: 'i-lucide-book-open',
  active: route.path.startsWith('/pohon/getting-started'),
}, {
  label: 'Components',
  to: '/pohon/components',
  icon: 'i-lucide-box',
  active: route.path.startsWith('/pohon/components'),
}, {
  label: 'Theme',
  icon: 'i-lucide-palette',
  to: '/theme',
  target: '_blank',
}, {
  label: 'Releases',
  icon: 'i-lucide-rocket',
  to: 'https://github.com/vinicunca/pohon/releases',
  target: '_blank',
}]);
</script>

<template>
  <PHeader>
    <template #title>
      <Logo class="h-6 w-auto" />
    </template>

    <PNavigationMenu :items="items" />

    <template #right>
      <PColorModeButton />

      <PTooltip
        text="Open on GitHub"
        :kbds="['meta', 'G']"
      >
        <PButton
          color="neutral"
          variant="ghost"
          to="https://github.com/vinicunca/pohon"
          target="_blank"
          icon="i-simple-icons-github"
          aria-label="GitHub"
        />
      </PTooltip>
    </template>

    <template #body>
      <PNavigationMenu
        :items="items"
        orientation="vertical"
        class="-mx-2.5"
      />
    </template>
  </PHeader>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type { NavigationMenuItem } from 'pohon-ui';

const route = useRoute();

const items = computed<Array<NavigationMenuItem>>(() => [{
  label: 'Docs',
  to: '/pohon/getting-started',
  icon: 'i-lucide-book-open',
  active: route.path.startsWith('/pohon/getting-started'),
}, {
  label: 'Components',
  to: '/pohon/components',
  icon: 'i-lucide-box',
  active: route.path.startsWith('/pohon/components'),
}, {
  label: 'Theme',
  icon: 'i-lucide-palette',
  to: '/theme',
  target: '_blank',
}, {
  label: 'Releases',
  icon: 'i-lucide-rocket',
  to: 'https://github.com/vinicunca/pohon/releases',
  target: '_blank',
}]);
</script>

<template>
  <PHeader>
    <template #title>
      <Logo class="h-6 w-auto" />
    </template>

    <PNavigationMenu :items="items" />

    <template #right>
      <PColorModeButton />

      <PTooltip
        text="Open on GitHub"
        :kbds="['meta', 'G']"
      >
        <PButton
          color="neutral"
          variant="ghost"
          to="https://github.com/vinicunca/pohon"
          target="_blank"
          icon="i-simple-icons-github"
          aria-label="GitHub"
        />
      </PTooltip>
    </template>

    <template #body>
      <PNavigationMenu
        :items="items"
        orientation="vertical"
        class="-mx-2.5"
      />
    </template>
  </PHeader>
</template>

Toggle

Use the toggle prop to customize the toggle button displayed on mobile.

You can pass any property from the Button component to customize it.

<script setup lang="ts">
import type { NavigationMenuItem } from 'pohon-ui';

const route = useRoute();

const items = computed<Array<NavigationMenuItem>>(() => [{
  label: 'Docs',
  to: '/pohon/getting-started',
  icon: 'i-lucide-book-open',
  active: route.path.startsWith('/pohon/getting-started'),
}, {
  label: 'Components',
  to: '/pohon/components',
  icon: 'i-lucide-box',
  active: route.path.startsWith('/pohon/components'),
}, {
  label: 'Theme',
  icon: 'i-lucide-palette',
  to: '/theme',
  target: '_blank',
}, {
  label: 'Releases',
  icon: 'i-lucide-rocket',
  to: 'https://github.com/vinicunca/pohon/releases',
  target: '_blank',
}]);
</script>

<template>
  <PHeader
    :toggle="{
      color: 'primary',
      variant: 'subtle',
      class: 'rounded-full',
    }"
  >
    <template #title>
      <Logo class="h-6 w-auto" />
    </template>

    <PNavigationMenu :items="items" />

    <template #right>
      <PColorModeButton />

      <PTooltip
        text="Open on GitHub"
        :kbds="['meta', 'G']"
      >
        <PButton
          color="neutral"
          variant="ghost"
          to="https://github.com/vinicunca/pohon"
          target="_blank"
          icon="i-simple-icons-github"
          aria-label="GitHub"
        />
      </PTooltip>
    </template>

    <template #body>
      <PNavigationMenu
        :items="items"
        orientation="vertical"
        class="-mx-2.5"
      />
    </template>
  </PHeader>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type { NavigationMenuItem } from 'pohon-ui';

const route = useRoute();

const items = computed<Array<NavigationMenuItem>>(() => [{
  label: 'Docs',
  to: '/pohon/getting-started',
  icon: 'i-lucide-book-open',
  active: route.path.startsWith('/pohon/getting-started'),
}, {
  label: 'Components',
  to: '/pohon/components',
  icon: 'i-lucide-box',
  active: route.path.startsWith('/pohon/components'),
}, {
  label: 'Theme',
  icon: 'i-lucide-palette',
  to: '/theme',
  target: '_blank',
}, {
  label: 'Releases',
  icon: 'i-lucide-rocket',
  to: 'https://github.com/vinicunca/pohon/releases',
  target: '_blank',
}]);
</script>

<template>
  <PHeader
    :toggle="{
      color: 'primary',
      variant: 'subtle',
      class: 'rounded-full',
    }"
  >
    <template #title>
      <Logo class="h-6 w-auto" />
    </template>

    <PNavigationMenu :items="items" />

    <template #right>
      <PColorModeButton />

      <PTooltip
        text="Open on GitHub"
        :kbds="['meta', 'G']"
      >
        <PButton
          color="neutral"
          variant="ghost"
          to="https://github.com/vinicunca/pohon"
          target="_blank"
          icon="i-simple-icons-github"
          aria-label="GitHub"
        />
      </PTooltip>
    </template>

    <template #body>
      <PNavigationMenu
        :items="items"
        orientation="vertical"
        class="-mx-2.5"
      />
    </template>
  </PHeader>
</template>

Toggle Side

Use the toggle-side prop to change the side of the toggle button. Defaults to right.

<script setup lang="ts">
import type { NavigationMenuItem } from 'pohon-ui';

const route = useRoute();

const items = computed<Array<NavigationMenuItem>>(() => [{
  label: 'Docs',
  to: '/pohon/getting-started',
  icon: 'i-lucide-book-open',
  active: route.path.startsWith('/pohon/getting-started'),
}, {
  label: 'Components',
  to: '/pohon/components',
  icon: 'i-lucide-box',
  active: route.path.startsWith('/pohon/components'),
}, {
  label: 'Theme',
  icon: 'i-lucide-palette',
  to: '/theme',
  target: '_blank',
}, {
  label: 'Releases',
  icon: 'i-lucide-rocket',
  to: 'https://github.com/vinicunca/pohon/releases',
  target: '_blank',
}]);
</script>

<template>
  <PHeader toggle-side="left">
    <template #title>
      <Logo class="h-6 w-auto" />
    </template>

    <PNavigationMenu :items="items" />

    <template #right>
      <PColorModeButton />

      <PTooltip
        text="Open on GitHub"
        :kbds="['meta', 'G']"
      >
        <PButton
          color="neutral"
          variant="ghost"
          to="https://github.com/vinicunca/pohon"
          target="_blank"
          icon="i-simple-icons-github"
          aria-label="GitHub"
        />
      </PTooltip>
    </template>

    <template #body>
      <PNavigationMenu
        :items="items"
        orientation="vertical"
        class="-mx-2.5"
      />
    </template>
  </PHeader>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type { NavigationMenuItem } from 'pohon-ui';

const route = useRoute();

const items = computed<Array<NavigationMenuItem>>(() => [{
  label: 'Docs',
  to: '/pohon/getting-started',
  icon: 'i-lucide-book-open',
  active: route.path.startsWith('/pohon/getting-started'),
}, {
  label: 'Components',
  to: '/pohon/components',
  icon: 'i-lucide-box',
  active: route.path.startsWith('/pohon/components'),
}, {
  label: 'Theme',
  icon: 'i-lucide-palette',
  to: '/theme',
  target: '_blank',
}, {
  label: 'Releases',
  icon: 'i-lucide-rocket',
  to: 'https://github.com/vinicunca/pohon/releases',
  target: '_blank',
}]);
</script>

<template>
  <PHeader toggle-side="left">
    <template #title>
      <Logo class="h-6 w-auto" />
    </template>

    <PNavigationMenu :items="items" />

    <template #right>
      <PColorModeButton />

      <PTooltip
        text="Open on GitHub"
        :kbds="['meta', 'G']"
      >
        <PButton
          color="neutral"
          variant="ghost"
          to="https://github.com/vinicunca/pohon"
          target="_blank"
          icon="i-simple-icons-github"
          aria-label="GitHub"
        />
      </PTooltip>
    </template>

    <template #body>
      <PNavigationMenu
        :items="items"
        orientation="vertical"
        class="-mx-2.5"
      />
    </template>
  </PHeader>
</template>

Examples

With animated toggle

Use the #toggle slot to replace the default toggle button with a custom animated hamburger icon using Motion Vue.

<script setup lang="ts">
import type { VariantType } from 'motion-v';
import type { NavigationMenuItem } from 'pohon-ui';
import { motion } from 'motion-v';

const route = useRoute();

const items = computed<Array<NavigationMenuItem>>(() => [{
  label: 'Docs',
  to: '/pohon/getting-started',
  icon: 'i-lucide-book-open',
  active: route.path.startsWith('/pohon/getting-started'),
}, {
  label: 'Components',
  to: '/pohon/components',
  icon: 'i-lucide-box',
  active: route.path.startsWith('/pohon/components'),
}, {
  label: 'Theme',
  icon: 'i-lucide-palette',
  to: '/theme',
  target: '_blank',
}, {
  label: 'Releases',
  icon: 'i-lucide-rocket',
  to: 'https://github.com/vinicunca/pohon/releases',
  target: '_blank',
}]);

const variants: { [k: string]: VariantType | ((custom: unknown) => VariantType) } = {
  normal: {
    rotate: 0,
    y: 0,
    opacity: 1,
  },
  close: (custom: unknown) => {
    const c = custom as number;
    return {
      rotate: c === 1 ? 45 : c === 3 ? -45 : 0,
      y: c === 1 ? 6 : c === 3 ? -6 : 0,
      opacity: c === 2 ? 0 : 1,
      transition: {
        type: 'spring',
        stiffness: 260,
        damping: 20,
      },
    };
  },
};
</script>

<template>
  <PHeader>
    <template #title>
      <Logo class="h-6 w-auto" />
    </template>

    <PNavigationMenu :items="items" />

    <template #right>
      <PColorModeButton />

      <PTooltip
        text="Open on GitHub"
        :kbds="['meta', 'G']"
      >
        <PButton
          color="neutral"
          variant="ghost"
          to="https://github.com/vinicunca/pohon"
          target="_blank"
          icon="i-simple-icons-github"
          aria-label="GitHub"
        />
      </PTooltip>
    </template>

    <template #toggle="{ open, toggle, ui }">
      <PButton
        size="sm"
        variant="ghost"
        color="neutral"
        square
        :class="ui.toggle({ toggleSide: 'right' })"
        @click="toggle"
      >
        <svg
          xmlns="http://www.w3.org/2000/svg"
          class="size-5"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <motion.line
            x1="4"
            y1="6"
            x2="20"
            y2="6"
            :variants="variants"
            :animate="open ? 'close' : 'normal'"
            :custom="1"
            tabindex="-1"
          />
          <motion.line
            x1="4"
            y1="12"
            x2="20"
            y2="12"
            :variants="variants"
            :animate="open ? 'close' : 'normal'"
            :custom="2"
            tabindex="-1"
          />
          <motion.line
            x1="4"
            y1="18"
            x2="20"
            y2="18"
            :variants="variants"
            :animate="open ? 'close' : 'normal'"
            :custom="3"
            tabindex="-1"
          />
        </svg>
      </PButton>
    </template>

    <template #body>
      <PNavigationMenu
        :items="items"
        orientation="vertical"
        class="-mx-2.5"
      />
    </template>
  </PHeader>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type { VariantType } from 'motion-v';
import type { NavigationMenuItem } from 'pohon-ui';
import { motion } from 'motion-v';

const route = useRoute();

const items = computed<Array<NavigationMenuItem>>(() => [{
  label: 'Docs',
  to: '/pohon/getting-started',
  icon: 'i-lucide-book-open',
  active: route.path.startsWith('/pohon/getting-started'),
}, {
  label: 'Components',
  to: '/pohon/components',
  icon: 'i-lucide-box',
  active: route.path.startsWith('/pohon/components'),
}, {
  label: 'Theme',
  icon: 'i-lucide-palette',
  to: '/theme',
  target: '_blank',
}, {
  label: 'Releases',
  icon: 'i-lucide-rocket',
  to: 'https://github.com/vinicunca/pohon/releases',
  target: '_blank',
}]);

const variants: { [k: string]: VariantType | ((custom: unknown) => VariantType) } = {
  normal: {
    rotate: 0,
    y: 0,
    opacity: 1,
  },
  close: (custom: unknown) => {
    const c = custom as number;
    return {
      rotate: c === 1 ? 45 : c === 3 ? -45 : 0,
      y: c === 1 ? 6 : c === 3 ? -6 : 0,
      opacity: c === 2 ? 0 : 1,
      transition: {
        type: 'spring',
        stiffness: 260,
        damping: 20,
      },
    };
  },
};
</script>

<template>
  <PHeader>
    <template #title>
      <Logo class="h-6 w-auto" />
    </template>

    <PNavigationMenu :items="items" />

    <template #right>
      <PColorModeButton />

      <PTooltip
        text="Open on GitHub"
        :kbds="['meta', 'G']"
      >
        <PButton
          color="neutral"
          variant="ghost"
          to="https://github.com/vinicunca/pohon"
          target="_blank"
          icon="i-simple-icons-github"
          aria-label="GitHub"
        />
      </PTooltip>
    </template>

    <template #toggle="{ open, toggle, ui }">
      <PButton
        size="sm"
        variant="ghost"
        color="neutral"
        square
        :class="ui.toggle({ toggleSide: 'right' })"
        @click="toggle"
      >
        <svg
          xmlns="http://www.w3.org/2000/svg"
          class="size-5"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <motion.line
            x1="4"
            y1="6"
            x2="20"
            y2="6"
            :variants="variants"
            :animate="open ? 'close' : 'normal'"
            :custom="1"
            tabindex="-1"
          />
          <motion.line
            x1="4"
            y1="12"
            x2="20"
            y2="12"
            :variants="variants"
            :animate="open ? 'close' : 'normal'"
            :custom="2"
            tabindex="-1"
          />
          <motion.line
            x1="4"
            y1="18"
            x2="20"
            y2="18"
            :variants="variants"
            :animate="open ? 'close' : 'normal'"
            :custom="3"
            tabindex="-1"
          />
        </svg>
      </PButton>
    </template>

    <template #body>
      <PNavigationMenu
        :items="items"
        orientation="vertical"
        class="-mx-2.5"
      />
    </template>
  </PHeader>
</template>

Within app.vue

Use the Header component in your app.vue or in a layout:

app.vue
<script setup lang="ts">
import type { NavigationMenuItem } from 'pohon-ui';

const route = useRoute();

const items = computed<Array<NavigationMenuItem>>(() => [
  {
    label: 'Docs',
    to: '/pohon/getting-started',
    active: route.path.startsWith('/pohon/getting-started')
  },
  {
    label: 'Components',
    to: '/pohon/components',
    active: route.path.startsWith('/pohon/components')
  },
  {
    label: 'Theme',
    to: '/theme',
    target: '_blank'
  },
  {
    label: 'Releases',
    to: 'https://github.com/vinicunca/pohon/releases',
    target: '_blank'
  }
]);
</script>

<template>
  <PApp>
    <PHeader>
      <template #title>
        <Logo class="h-6 w-auto" />
      </template>

      <PNavigationMenu :items="items" />

      <template #right>
        <PColorModeButton />

        <PButton
          color="neutral"
          variant="ghost"
          to="https://github.com/vinicunca/pohon"
          target="_blank"
          icon="i-simple-icons-github"
          aria-label="GitHub"
        />
      </template>

      <template #body>
        <PNavigationMenu
          :items="items"
          orientation="vertical"
          class="-mx-2.5"
        />
      </template>
    </PHeader>

    <PMain>
      <NuxtLayout>
        <NuxtPage />
      </NuxtLayout>
    </PMain>

    <PFooter />
  </PApp>
</template>

API

Props

Prop Default Type

Slots

Slot Type

Emits

Event Type

Theme

app.config.ts
export default defineAppConfig({
  ui: {
    header: {
      slots: {
        root: 'bg-background/75 border-border border-b h-$ui-header-height top-0 sticky z-50 backdrop-blur-sm',
        container: 'flex items-center justify-between gap-3 h-full',
        left: 'lg:flex-1 flex items-center gap-1.5',
        center: 'hidden lg:flex',
        right: 'flex items-center justify-end lg:flex-1 gap-1.5',
        title: 'shrink-0 font-700 text-xl color-text-highlighted flex items-end gap-1.5',
        toggle: 'lg:hidden',
        content: 'lg:hidden',
        overlay: 'lg:hidden',
        header: 'px-4 flex shrink-0 gap-3 h-$ui-header-height items-center justify-between sm:px-6',
        body: 'p-4 sm:p-6 overflow-y-auto'
      },
      variants: {
        toggleSide: {
          left: {
            toggle: '-ms-1.5'
          },
          right: {
            toggle: '-me-1.5'
          }
        }
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from 'pohon-ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        header: {
          slots: {
            root: 'bg-background/75 border-border border-b h-$ui-header-height top-0 sticky z-50 backdrop-blur-sm',
            container: 'flex items-center justify-between gap-3 h-full',
            left: 'lg:flex-1 flex items-center gap-1.5',
            center: 'hidden lg:flex',
            right: 'flex items-center justify-end lg:flex-1 gap-1.5',
            title: 'shrink-0 font-700 text-xl color-text-highlighted flex items-end gap-1.5',
            toggle: 'lg:hidden',
            content: 'lg:hidden',
            overlay: 'lg:hidden',
            header: 'px-4 flex shrink-0 gap-3 h-$ui-header-height items-center justify-between sm:px-6',
            body: 'p-4 sm:p-6 overflow-y-auto'
          },
          variants: {
            toggleSide: {
              left: {
                toggle: '-ms-1.5'
              },
              right: {
                toggle: '-me-1.5'
              }
            }
          }
        }
      }
    })
  ]
})

Changelog

No recent changes