Lien d’en-tête - DsfrHeaderMenuLink 
🌟 Introduction 
Le composant DsfrHeaderMenuLink offre une flexibilité pour des liens internes, externes, des boutons, et même des liens mailto, tout en intégrant la possibilité d'ajouter des icônes du DSFR ou grâce à Iconify (cf. la documentation sur les icônes VueDsfr).
📐 Structure 
- <DsfrHeaderMenuLink>: Le composant principal.- Utilise <component :is="...">pour rendre dynamiquement le bon type d'élément (lien, bouton, ou RouterLink).
- Intègre des icônes avec <VIcon>si nécessaire.
 
- Utilise 
🛠️ Props 
| Propriété | Type | Description | Valeur par défaut | 
|---|---|---|---|
| button | boolean | Si vrai, le composant se comporte comme un bouton. | undefined | 
| icon | string | VIcon['$props'] | Nom de l'icône ou les props de l'icône à utiliser. | undefined | 
| iconAttrs | VIcon['$props'] & import('vue').HTMLAttributes | Attributs supplémentaires pour l'icône. | {} | 
| iconRight | boolean | Si vrai, positionne l'icône à droite du label. | false | 
| label | string | Texte du lien ou du bouton. | '' | 
| target | string | Cible du lien, par exemple _blankpour ouvrir dans un nouvel onglet. | '_self' | 
| onClick | Function | Fonction à exécuter lors du clic sur le composant. | () => undefined | 
| to | import('vue-router').RouteLocationRaw | Destination pour le routeur Vue, si utilisé comme lien de navigation interne. | undefined | 
| href | string | URL pour les liens externes. | undefined | 
📡Événements 
- click: Événement déclenché lorsque l'utilisateur clique sur le composant.
🧩 Slots 
Pas de slots spécifiques pour ce composant. Il utilise le label pour afficher le texte du lien ou du bouton.
📝 Exemples 
Ce composant est utilisé en interne dans DsfrHeader. Il n’y a pas de raison de l’utiliser en dehors.
⚙️ Code source du composant 
vue
<script lang="ts" setup>
import type { DsfrHeaderMenuLinkProps } from './DsfrHeader.types'
import { computed } from 'vue'
import VIcon from '../VIcon/VIcon.vue'
export type { DsfrHeaderMenuLinkProps }
const props = withDefaults(defineProps<DsfrHeaderMenuLinkProps>(), {
  icon: undefined,
  iconAttrs: () => ({}),
  onClick: () => undefined,
  target: '_self',
  label: '',
  href: undefined,
  to: undefined,
  path: '',
})
const isPathString = computed(() => {
  return typeof props.path === 'string'
})
const isExternalLink = computed(() => {
  return props.href?.startsWith('http') ||
    (isPathString.value && (props.path as string).startsWith('http')) ||
    (typeof props.to === 'string' && (props.to as string).startsWith('http'))
})
const isMailto = computed(() => {
  return props.href?.startsWith('mailto') ||
    (isPathString.value && (props.path as string).startsWith('mailto')) ||
    (typeof props.to === 'string' && (props.to as string).startsWith('mailto'))
})
const is = computed(() => {
  if (props.button) {
    return 'button'
  }
  return isExternalLink.value || isMailto.value ? 'a' : 'RouterLink'
})
const actualHref = computed(() => {
  if (!isExternalLink.value && !isMailto.value) {
    return undefined
  }
  return props.to ?? props.href ?? props.path
})
const actualTo = computed(() => {
  if (isExternalLink.value || isMailto.value) {
    return undefined
  }
  return props.to ?? props.path
})
const linkData = computed(() => {
  return actualTo.value ? { to: actualTo.value } : { href: actualHref.value }
})
const dsfrIcon = computed(() => typeof props.icon === 'string' && props.icon.startsWith('fr-icon-'))
const defaultScale = 1
const iconProps = computed(() => typeof props.icon === 'string'
  ? { name: props.icon, scale: defaultScale, ...(props.iconAttrs ?? {}) }
  : { scale: defaultScale, ...(props.icon ?? {}), ...(props.iconAttrs ?? {}) },
)
</script>
<template>
  <component
    :is="is"
    class="fr-btn"
    :class="{
      'fr-btn--icon-right': dsfrIcon && iconRight,
      'fr-btn--icon-left': dsfrIcon && !iconRight,
      [String(icon)]: dsfrIcon,
    }"
    v-bind="linkData"
    :target="target"
    @click.stop="onClick($event)"
  >
    <template
      v-if="!dsfrIcon && (icon || iconAttrs?.name) && !iconRight"
    >
      <VIcon
        class="fr-mr-1w"
        v-bind="iconProps"
      />
    </template>
    {{ label }}
    <template
      v-if="!dsfrIcon && (icon || iconAttrs?.name) && iconRight"
    >
      <VIcon
        class="fr-ml-1w"
        v-bind="iconProps"
      />
    </template>
  </component>
</template>ts
import type { DsfrLanguageSelectorProps } from '../DsfrLanguageSelector/DsfrLanguageSelector.types'
import type VIcon from '../VIcon/VIcon.vue'
import type { HTMLAttributes, StyleValue } from 'vue'
import type { RouteLocationRaw } from 'vue-router'
export type DsfrHeaderMenuLinkProps = {
  button?: boolean
  icon?: string | InstanceType<typeof VIcon>['$props']
  iconAttrs?: InstanceType<typeof VIcon>['$props'] & HTMLAttributes
  iconRight?: boolean
  label?: string
  target?: string
  onClick?: ($event: MouseEvent) => void
  to?: RouteLocationRaw
  /**
   * @deprecated Use the prop `to` instead
   */
  href?: string
  /**
   * @deprecated Use the prop `to` instead
   */
  path?: string
}
export type DsfrHeaderProps = {
  searchbarId?: string
  serviceTitle?: string
  serviceDescription?: string
  homeTo?: string
  logoText?: string | string[]
  modelValue?: string
  operatorImgAlt?: string
  operatorImgSrc?: string
  operatorImgStyle?: StyleValue
  placeholder?: string
  quickLinks?: (DsfrHeaderMenuLinkProps & HTMLAttributes)[]
  languageSelector?: DsfrLanguageSelectorProps
  searchLabel?: string
  quickLinksAriaLabel?: string
  showSearch?: boolean
  showSearchLabel?: string
  showBeta?: boolean
  menuLabel?: string
  menuModalLabel?: string
  closeMenuModalLabel?: string
  homeLabel?: string
}