Méga-menu de navigation - DsfrNavigationMegaMenu
🌟 Introduction
Le méga-menu de navigation est un composant complexe qui affiche un menu déroulant étendu avec plusieurs catégories organisées en grille. Il offre une navigation riche avec descriptions et liens structurés.
Le composant DsfrNavigationMegaMenu
crée un menu déroulant expansif avec animations de collapse/expand, idéal pour présenter une navigation hiérarchique complexe avec descriptions et liens organisés.
Important
Ce composant NE devrait PAS être utilisé directement, il est utilisé en interne par son parent DsfrNavigation
📐 Structure
Le méga-menu de navigation est composé des éléments suivants :
- un bouton déclencheur avec le titre (prop
title
) - un conteneur expansible avec animations de collapse
- une zone de leadership avec titre, description et lien principal
- une grille de catégories de menu (prop
menus
) - un bouton de fermeture intégré
- des slots pour contenu personnalisé
🛠️ Props
nom | type | défaut | obligatoire | description |
---|---|---|---|---|
title | string | ✅ | Titre du méga-menu affiché dans le bouton et l'en-tête | |
id | string | () => useRandomId(...) | Identifiant unique pour le méga-menu | |
description | string | '' | Description affichée dans la zone de leadership | |
link | { to: RouteLocationRaw, text: string } | { to: '#', text: 'Voir toute la rubrique' } | Lien principal vers la page complète de la rubrique | |
menus | DsfrNavigationMegaMenuCategoryProps[] | [] | Tableau des catégories de menu à afficher | |
expandedId | string | '' | ID du menu actuellement expansé | |
active | boolean | false | Indique si ce méga-menu est actuellement actif |
📡 Événements
DsfrNavigationMegaMenu
déclenche l'événement suivant :
nom | donnée (payload) | description |
---|---|---|
toggleId | string | Émis lors du clic sur le bouton pour ouvrir/fermer le menu |
🧩 Slots
DsfrNavigationMegaMenu
possède deux slots pour personnaliser le contenu.
nom | description |
---|---|
description | Slot nommé pour le contenu personnalisé de la description |
default | Slot par défaut pour le contenu personnalisé du méga-menu |
📝 Exemples
Exemple d'utilisation de DsfrNavigationMegaMenu
dans une navigation :
<template>
<DsfrNavigation :nav-items="navItems">
<DsfrNavigationMegaMenu
title="Services"
description="Découvrez tous nos services publics"
:link="{ to: '/services', text: 'Voir tous les services' }"
:menus="serviceMenus"
:expanded-id="expandedMenuId"
@toggle-id="handleToggle"
/>
</DsfrNavigation>
</template>
⚙️ Code source du composant
<script lang="ts" setup>
import type { DsfrNavigationMegaMenuProps } from './DsfrNavigation.types'
import { computed, onMounted, watch } from 'vue'
import { useCollapsable } from '../../composables'
import { useRandomId } from '../../utils/random-utils'
import DsfrNavigationMegaMenuCategory from './DsfrNavigationMegaMenuCategory.vue'
export type { DsfrNavigationMegaMenuProps }
const props = withDefaults(defineProps<DsfrNavigationMegaMenuProps>(), {
id: () => useRandomId('mega-menu'),
description: '',
link: () => ({ to: '#', text: 'Voir toute la rubrique' }),
menus: () => [],
expandedId: '',
})
defineEmits<{ (event: 'toggleId', id: string): void }>()
const {
collapse,
collapsing,
cssExpanded,
doExpand,
onTransitionEnd,
} = useCollapsable()
const expanded = computed(() => {
return props.id === props.expandedId
})
watch(expanded, (newValue, oldValue) => {
if (newValue !== oldValue) {
/*
* @see https://github.com/GouvernementFR/dsfr/blob/main/src/core/script/collapse/collapse.js
*/
doExpand(newValue)
}
})
onMounted(() => {
// NavigationMegaMenu can be expanded by default
// We need to trigger the expand animation at mounted
if (expanded.value) {
doExpand(true)
}
})
</script>
<template>
<button
class="fr-nav__btn"
:aria-expanded="expanded"
:aria-current="active || undefined"
:aria-controls="id"
@click="$emit('toggleId', id)"
>
{{ title }}
</button>
<div
:id="id"
ref="collapse"
data-testid="mega-menu-wrapper"
class="fr-collapse fr-mega-menu"
tabindex="-1"
: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)"
>
<div class="fr-container fr-container--fluid fr-container-lg">
<button
class="fr-link--close fr-link"
aria-controls="mega-menu-695"
@click="$emit('toggleId', id)"
>
Fermer
</button>
<div
class="fr-grid-row fr-grid-row-lg--gutters"
>
<div class="fr-col-12 fr-col-lg-8 fr-col-offset-lg-4--right fr-mb-4v">
<div class="fr-mega-menu__leader">
<h4 class="fr-h4 fr-mb-2v">
{{ title }}
</h4>
<p class="fr-hidden fr-displayed-lg">
{{ description }}
<!-- @slot Slot par défaut pour le contenu de la description du mega-menu. Sera dans `<p class="fr-text--sm">` -->
<slot name="description" />
</p>
<RouterLink
class="fr-link fr-icon-arrow-right-line fr-link--icon-right fr-link--align-on-content"
:to="link.to"
>
{{ link.text }}
</RouterLink>
</div>
</div>
<!-- @slot Slot par défaut pour le contenu du mega-menu. Sera dans `<div class="fr-grid-row fr-grid-row--gutters">` -->
<slot />
<DsfrNavigationMegaMenuCategory
v-for="(menu, idx) of menus"
:key="idx"
v-bind="menu"
/>
</div>
</div>
</div>
</template>
<style scoped>
.fr-collapse--expanded {
max-height: none !important;
}
</style>
import type { RouteLocationRaw } from 'vue-router'
export type DsfrNavigationMenuLinkProps = {
id?: string
to?: string | RouteLocationRaw
text?: string
icon?: string
onClick?: ($event: MouseEvent) => void
}
export type DsfrNavigationMenuItemProps = {
id?: string
active?: boolean
}
export type DsfrNavigationMenuProps = {
id?: string
title: string
links?: DsfrNavigationMenuLinkProps[]
expandedId?: string
active?: boolean
}
export type DsfrNavigationItemProps = {
id?: string
active?: boolean
}
export type DsfrNavigationMegaMenuCategoryProps = {
title: string
active?: boolean
links: DsfrNavigationMenuLinkProps[]
}
export type DsfrNavigationMegaMenuProps = {
id?: string
title: string
description?: string
link?: { to: RouteLocationRaw, text: string }
menus?: DsfrNavigationMegaMenuCategoryProps[]
expandedId?: string
active?: boolean
}
export type DsfrNavigationMenuLinks = (DsfrNavigationMenuLinkProps | DsfrNavigationMegaMenuProps | DsfrNavigationMenuProps)[]
export type DsfrNavigationProps = {
id?: string
label?: string
navItems: (
DsfrNavigationMenuLinkProps
| DsfrNavigationMenuProps
| DsfrNavigationMegaMenuProps
)[]
}