Skip to content

Fil d’ariane - DsfrBreadcrumb

🌟 Introduction

Bienvenue à la documentation du composant DsfrBreadcrumb ! Ce composant est un véritable GPS pour vos interfaces utilisateur, guidant les utilisateurs à travers les différents niveaux de votre application avec aisance et élégance. Utilisons TypeScript et Vue pour explorer ses fonctionnalités.

Le fil d’Ariane est un système de navigation secondaire qui permet à l’utilisateur de se situer sur le site qu’il consulte.

🏅 La documentation sur le fil d’Ariane sur le DSFR

La story sur le fil d’Ariane sur le storybook de VueDsfr

📐 Structure

Dans l’ordre, il se compose des éléments suivants :

  • un lien menant à la racine du site (page d’accueil) - obligatoire ;
  • des liens vers les pages séparant la racine du site de la page courante - obligatoire si la hiérarchie du site comporte plus d’un niveau ;
  • la page courante, seul élément non cliquable - obligatoire.

🛠️ Props

NomTypeDéfautDescription
breadcrumbIdString() => getRandomId('breadcrumb')Identifiant unique pour le composant breadcrumb, généré automatiquement pour assurer l'accessibilité.
linksArray() => [{ text: '' }]Un tableau d'objets représentant les liens dans le fil d'Ariane. Chaque objet peut avoir une propriété 'text' et, optionnellement, 'to' pour les routes.
navigationLabelString'vous êtes ici :'Label affiché sur la balise nav du fil d’Ariane.
showBreadcrumbLabelString'Voir le fil d’Ariane'Label du bouton d'affichage du fil d’Ariane.

📡 Évenements

Ce composant n'émet pas directement d'événements, mais vous pouvez écouter les événements de clic sur les liens individuels si nécessaire.

🧩 Slots

Pas de slots définis pour DsfrBreadcrumb. Le contenu est entièrement géré via les props.

📝 Exemples

Voici un exemple d'utilisation de DsfrBreadcrumb  :

vue
<DsfrBreadcrumb
  breadcrumbId="mon-fil-dariane"
  :links="[
    { text: 'Accueil', to: '/' },
    { text: 'Bibliothèque', to: '/bibliotheque' },
    { text: 'Livre', to: '/livre' }
    { text: 'Le Seigneur des anneaux' }
  ]"
/>
vue
<script lang="ts" setup>
import { getCurrentInstance } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'

import DsfrBreadcrumb from '../DsfrBreadcrumb.vue'

const app = getCurrentInstance()
app?.appContext.app.use(
  createRouter({
    history: createWebHistory(),
    routes: [
      { path: '/', component: { template: '<div>Accueil</div>' } },
      { path: '/bibliotheque', component: { template: '<div>Bibliothèque</div>' } },
      { path: '/livre', component: { template: '<div>Livre</div>' } },
    ],
  }),
)
</script>

<template>
  <div class="fr-container fr-my-2v">
    <DsfrBreadcrumb
      breadcrumb-id="mon-fil-dariane"
      :links="[
        { text: 'Accueil', to: '/' },
        { text: 'Bibliothèque', to: '/bibliotheque' },
        { text: 'Livre', to: '/livre' },
        { text: 'Le Seigneur des anneaux' },
      ]"
    />
  </div>
</template>
vue
<script setup lang="ts">
import { ref, watch } from 'vue'

import { useCollapsable } from '../../composables'
import { getRandomId } from '../../utils/random-utils'

import type { DsfrBreadcrumbProps } from './DsfrBreadcrumb.types'

export type { DsfrBreadcrumbProps }

withDefaults(defineProps<DsfrBreadcrumbProps>(), {
  breadcrumbId: () => getRandomId('breadcrumb'),
  links: () => [{ text: '' }],
  navigationLabel: 'vous êtes ici :',
  showBreadcrumbLabel: 'Voir le fil d’Ariane',
})

const {
  collapse,
  collapsing,
  cssExpanded,
  doExpand,
  onTransitionEnd,
} = useCollapsable()

const expanded = ref(false)

watch(expanded, (newValue, oldValue) => {
  if (newValue !== oldValue) {
    /*
     * @see https://github.com/GouvernementFR/dsfr/blob/main/src/core/script/collapse/collapse.js
     */
    doExpand(newValue)
  }
})
</script>

<template>
  <nav
    role="navigation"
    class="fr-breadcrumb"
    :aria-label="navigationLabel"
  >
    <button
      v-show="!expanded"
      class="fr-breadcrumb__button"
      :aria-expanded="expanded"
      :aria-controls="breadcrumbId"
      @click="expanded = !expanded"
    >
      {{ showBreadcrumbLabel }}
    </button>
    <div
      :id="breadcrumbId"
      ref="collapse"
      class="fr-collapse"
      :class="{
        'fr-collapse--expanded': cssExpanded, // Need to use a separate data to add/remove the class after a RAF
        'fr-collapsing': collapsing,
      }"
      @transitionend="onTransitionEnd(expanded)"
    >
      <ol class="fr-breadcrumb__list">
        <li
          v-for="(link, index) in links"
          :key="index"
          class="fr-breadcrumb__item"
          data-testid="lis"
        >
          <RouterLink
            v-if="link.to"
            class="fr-breadcrumb__link"
            :to="link.to"
            :aria-current="index === links.length - 1 ? 'page' : undefined"
          >
            {{ link.text }}
          </RouterLink>
          <a
            v-if="!link.to"
            class="fr-breadcrumb__link"
            :aria-current="index === links.length - 1 ? 'page' : undefined"
          >{{ link.text }}</a>
        </li>
      </ol>
    </div>
  </nav>
</template>

Note :

Sur un écran plus large, le fil d’Ariane apparaîtrait directement en entier, sans le lien "Voir le fil d’Ariane"