---
name: header-checkout
title: Header Checkout
url: https://ui.frontic.com/components/templates/header-checkout.md
tier: templates
install: npx @frontic/ui add header-checkout
files:
  - components/templates/header-checkout/HeaderCheckout.vue
  - components/templates/header-checkout/index.ts
  - components/templates/header-checkout/types.ts
registryDependencies:
  - separator
  - stepper
  - text
dependencies:
  - "@lucide/vue"
---

# Header Checkout

Checkout header with the logo and a secure-checkout note, and the checkout steps in a band below: every step named on a wide screen, the current one and its position on a narrow one.

## Install

```sh
npx @frontic/ui add header-checkout
```

Built from: [Separator](https://ui.frontic.com/components/ui/separator.md), [Stepper](https://ui.frontic.com/components/ui/stepper.md), [Text](https://ui.frontic.com/lib/text.md)

npm packages: `@lucide/vue`

## Examples

```vue
<script setup lang="ts">
import { HeaderCheckout, type CheckoutStep } from '@/components/templates/header-checkout'

const steps: CheckoutStep[] = [
  { label: 'Address', value: 1 },
  { label: 'Shipping', value: 2 },
  { label: 'Payment', value: 3 },
  { label: 'Review', value: 4 },
]
</script>

<template>
  <div class="@container relative">
    <HeaderCheckout logo-text="Basecamp" :steps="steps" :step="3" />
  </div>
</template>
```

## API reference

### HeaderCheckout

Shows the logo and a secure-checkout note, with the checkout steps in a band below. Renders a `<header>`.

`data-slot="header-checkout"` · `HeaderCheckout.vue`

Styling: [`logo`](https://ui.frontic.com/DESIGN.md#logo); [`hint`](https://ui.frontic.com/DESIGN.md#hint). Change them there and every part that extends them follows.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `steps` (required) | `CheckoutStep[]` |  | The checkout steps in order; `value` shows in each step's circle. |
| `step` (required) | `number` |  | The current step, by `value`; earlier steps show a check. |
| `logoText` | `string` | `'STORE'` | Shown as the logo, or as the logo image's alt text when `logoSrc` is set. |
| `logoSrc` | `string` | `''` | URL of the logo image; `logoText` shows in its place when empty. |
| `homeHref` | `string` | `'/'` | Where the logo links to. |
| `stepsLabel` | `string` | `'Checkout steps'` | Screen-reader name of the step list. |
| `progressLabel` | `string` | `'Step {step} of {total}'` | Says where the shopper is when the band is too narrow to name every step; `{step}` and `{total}` stand for the position and the step count. |
| `secureLabel` | `string` | `'Secure Checkout'` | Shown next to the lock icon on wider screens. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

| Slot | Slot props | Description |
| --- | --- | --- |
| `navigation` | `{ steps: CheckoutStep[]; step: number; }` | Replaces the checkout stepper in the band; gets the steps and the current step. |

## Exports

```ts
import { type CheckoutStep } from '@/components/templates/header-checkout'
```

- `CheckoutStep`: below

```ts
interface CheckoutStep {
  label: string
  value: number
}
```

## Styling

| Part | Recipe |
| --- | --- |
| `default` | [`header-checkout`](https://ui.frontic.com/DESIGN.md#header-checkout) |
| `logo` | [`logo`](https://ui.frontic.com/DESIGN.md#logo) |
| `hint` | [`hint`](https://ui.frontic.com/DESIGN.md#hint) |
| `focus-ring` | [`focus-ring`](https://ui.frontic.com/DESIGN.md#focus-ring) |

States with a look of their own: focus.

## Source

`components/templates/header-checkout/HeaderCheckout.vue`

```vue
<script lang="ts">
/** Shows the logo and a secure-checkout note, with the checkout steps in a band below. */
export default {}
</script>

<script setup lang="ts">
import { LockIcon, CheckIcon } from '@lucide/vue'

import type { HTMLAttributes } from 'vue'
import { computed } from 'vue'
import { Separator } from '@library/components/ui/separator'
import { Stepper, StepperIndicator, StepperItem, StepperSeparator, StepperTitle, StepperTrigger } from '@library/components/ui/stepper'
import type { CheckoutStep } from './types'
import { interpolate } from '@library/lib/text'

const props = withDefaults(
  defineProps<{
    /** The checkout steps in order; `value` shows in each step's circle. */
    steps: CheckoutStep[]
    /** The current step, by `value`; earlier steps show a check. */
    step: number
    /** Shown as the logo, or as the logo image's alt text when `logoSrc` is set. */
    logoText?: string
    /** URL of the logo image; `logoText` shows in its place when empty. */
    logoSrc?: string
    /** Where the logo links to. */
    homeHref?: string
    /** Screen-reader name of the step list. */
    stepsLabel?: string
    /** Says where the shopper is when the band is too narrow to name every step; `{step}` and `{total}` stand for the position and the step count. */
    progressLabel?: string
    /** Shown next to the lock icon on wider screens. */
    secureLabel?: string
    class?: HTMLAttributes['class']
  }>(),
  {
    logoText: 'STORE',
    logoSrc: '',
    homeHref: '/',
    stepsLabel: 'Checkout steps',
    progressLabel: 'Step {step} of {total}',
    secureLabel: 'Secure Checkout',
  },
)
defineSlots<{
  /** Replaces the checkout stepper in the band; gets the steps and the current step. */
  navigation?: (props: { steps: CheckoutStep[]; step: number }) => unknown
}>()

const index = computed(() => props.steps.findIndex((s) => s.value === props.step))
const progress = computed(() => interpolate(props.progressLabel, { step: String(index.value + 1), total: String(props.steps.length) }))
</script>

<template>
  <header data-slot="header-checkout" :class="['fui-header-checkout @container relative', props.class]">
    <div class="mx-auto flex h-16 w-full max-w-384 items-center justify-between gap-6 px-4 @2xl:px-6 @5xl:px-8">
      <a :href="homeHref" data-slot="logo" class="fui-logo outline-none focus-visible:fui-focus-ring">
        <img v-if="logoSrc" :src="logoSrc" :alt="logoText" class="h-8 w-auto" />
        <template v-else>{{ logoText }}</template>
      </a>
      <div data-slot="hint" class="fui-hint">
        <div class="flex items-center gap-1.5">
          <LockIcon data-icon class="size-4" />
          <span class="hidden @2xl:inline">{{ secureLabel }}</span>
        </div>
      </div>
    </div>
    <template v-if="$slots.navigation || index >= 0">
      <Separator />
      <div data-slot="header-checkout-steps" class="mx-auto w-full max-w-3xl px-4 py-4 @2xl:px-6">
        <slot name="navigation" :steps="steps" :step="step">
          <Stepper :model-value="index + 1" :aria-label="stepsLabel" :status-label="() => progress">
            <StepperItem v-for="(item, at) in steps" :key="item.value" v-slot="{ state }" :step="at + 1">
              <StepperTrigger>
                <StepperIndicator>
                  <CheckIcon v-if="state === 'completed'" data-icon />
                  <template v-else>{{ item.value }}</template>
                </StepperIndicator>
                <StepperTitle>{{ item.label }}</StepperTitle>
              </StepperTrigger>
              <StepperSeparator v-if="at < steps.length - 1" />
            </StepperItem>
          </Stepper>
        </slot>
      </div>
    </template>
  </header>
</template>
```

`components/templates/header-checkout/types.ts`

```ts
export interface CheckoutStep {
  label: string
  value: number
}
```
