LinkGroup
Composant LinkGroup pour organiser et aligner des liens avec un espacement contrôlé. Supporte la propagation des props size, variant et underline aux liens enfants et la gestion spéciale des bordures pour les liens connectés.
Exemples d'utilisation
LinkGroup de base
Groupe simple avec gap par défaut
<template>
<SuLinkGroup>
<SuLink href="/home">Accueil</SuLink>
<SuLink href="/about">À propos</SuLink>
<SuLink href="/contact">Contact</SuLink>
</SuLinkGroup>
</template>Espacement (gap)
Différents espacements
<template>
<div>
<!-- Espacement petit -->
<SuLinkGroup gap="sm">
<SuLink href="/page1">Page 1</SuLink>
<SuLink href="/page2">Page 2</SuLink>
<SuLink href="/page3">Page 3</SuLink>
</SuLinkGroup>
<!-- Espacement moyen (défaut) -->
<SuLinkGroup gap="md">
<SuLink href="/page1">Page 1</SuLink>
<SuLink href="/page2">Page 2</SuLink>
<SuLink href="/page3">Page 3</SuLink>
</SuLinkGroup>
<!-- Espacement large -->
<SuLinkGroup gap="lg">
<SuLink href="/page1">Page 1</SuLink>
<SuLink href="/page2">Page 2</SuLink>
<SuLink href="/page3">Page 3</SuLink>
</SuLinkGroup>
<!-- Liens connectés -->
<SuLinkGroup gap="none">
<SuLink href="/first">Premier</SuLink>
<SuLink href="/middle">Milieu</SuLink>
<SuLink href="/last">Dernier</SuLink>
</SuLinkGroup>
</div>
</template>Propagation de la taille
Taille forcée sur tous les liens
<template>
<div>
<!-- Tous les liens seront en taille small -->
<SuLinkGroup size="sm">
<SuLink href="/link1">Petit lien 1</SuLink>
<SuLink href="/link2">Petit lien 2</SuLink>
<SuLink href="/link3">Petit lien 3</SuLink>
</SuLinkGroup>
<!-- Tous les liens seront en taille large -->
<SuLinkGroup size="lg">
<SuLink href="/link1">Grand lien 1</SuLink>
<SuLink href="/link2">Grand lien 2</SuLink>
<SuLink href="/link3">Grand lien 3</SuLink>
</SuLinkGroup>
</div>
</template>Propagation de la variante
Variante forcée sur tous les liens
<template>
<div>
<!-- Tous les liens seront primary -->
<SuLinkGroup variant="primary">
<SuLink href="/link1">Lien 1</SuLink>
<SuLink href="/link2">Lien 2</SuLink>
<SuLink href="/link3">Lien 3</SuLink>
</SuLinkGroup>
<!-- Tous les liens seront muted -->
<SuLinkGroup variant="muted">
<SuLink href="/link1">Lien 1</SuLink>
<SuLink href="/link2">Lien 2</SuLink>
<SuLink href="/link3">Lien 3</SuLink>
</SuLinkGroup>
</div>
</template>Séparateurs
Différents séparateurs
<template>
<!-- Breadcrumb avec slash -->
<SuLinkGroup separator="slash" variant="muted" size="sm">
<SuLink href="/">Accueil</SuLink>
<SuLink href="/products">Produits</SuLink>
<SuLink href="/products/laptops">Ordinateurs portables</SuLink>
</SuLinkGroup>
<!-- Navigation avec points -->
<SuLinkGroup separator="dot" variant="secondary">
<SuLink href="/home">Accueil</SuLink>
<SuLink href="/about">À propos</SuLink>
<SuLink href="/contact">Contact</SuLink>
</SuLinkGroup>
<!-- Étapes avec flèches -->
<SuLinkGroup separator="arrow" variant="primary">
<SuLink href="/step1">Étape 1</SuLink>
<SuLink href="/step2">Étape 2</SuLink>
<SuLink href="/step3">Étape 3</SuLink>
</SuLinkGroup>
</template>Direction verticale
Navigation verticale
<template>
<SuLinkGroup direction="vertical" variant="secondary">
<SuLink href="/dashboard">Tableau de bord</SuLink>
<SuLink href="/projects">Projets</SuLink>
<SuLink href="/team">Équipe</SuLink>
<SuLink href="/settings">Paramètres</SuLink>
</SuLinkGroup>
</template>Liens connectés avec variantes
Liens connectés avec différentes variantes
<script setup>
import { HomeIcon, UserIcon, CogIcon } from '@heroicons/vue/24/outline'
</script>
<template>
<div>
<!-- Liens connectés primary -->
<SuLinkGroup gap="none" variant="primary">
<SuLink href="/section1">Section 1</SuLink>
<SuLink href="/section2">Section 2</SuLink>
<SuLink href="/section3">Section 3</SuLink>
</SuLinkGroup>
<!-- Navigation d'icônes -->
<SuLinkGroup gap="none" variant="muted" size="sm">
<SuLink href="/home" :icon="HomeIcon" iconDisplay="only" aria-label="Accueil" />
<SuLink href="/profile" :icon="UserIcon" iconDisplay="only" aria-label="Profil" />
<SuLink href="/settings" :icon="CogIcon" iconDisplay="only" aria-label="Paramètres" />
</SuLinkGroup>
</div>
</template>API
Props
| Prop | Type | Default | Description |
|---|---|---|---|
gap | 'sm' | 'md' | 'lg' | 'none' | 'md' | Espacement entre les liens |
separator | 'none' | 'dot' | 'slash' | 'pipe' | 'arrow' | 'none' | Séparateur entre les liens |
size | 'sm' | 'md' | 'lg' | undefined | Taille forcée pour tous les liens |
variant | 'default' | 'primary' | 'secondary' | 'muted' | undefined | Variante forcée pour tous les liens |
underline | 'always' | 'hover' | 'never' | undefined | Soulignement forcé pour tous les liens |
direction | 'horizontal' | 'vertical' | 'horizontal' | Direction du groupe |
Attributs d'accessibilité
| Prop | Type | Default | Description |
|---|---|---|---|
ariaLabel | string | undefined | Label accessible pour le groupe |
ariaDescribedBy | string | undefined | ID de l'élément de description |
role | string | undefined | Rôle ARIA personnalisé (ex: 'navigation', 'group') |
Slots
| Slot | Description |
|---|---|
default | Liens à afficher dans le groupe |
Séparateurs
Les séparateurs permettent d'ajouter des caractères entre les liens pour améliorer la lisibilité :
🎯 Types de séparateurs
none: Aucun séparateur (défaut)dot: Point médian (•)slash: Barre oblique (/)pipe: Barre verticale (|)arrow: Flèche droite (→)
<!-- Breadcrumb avec slash -->
<SuLinkGroup separator="slash" variant="muted">
<SuLink href="/">Accueil</SuLink>
<SuLink href="/products">Produits</SuLink>
<SuLink href="/products/laptops">Ordinateurs portables</SuLink>
</SuLinkGroup>
<!-- Navigation avec points -->
<SuLinkGroup separator="dot" variant="secondary">
<SuLink href="/home">Accueil</SuLink>
<SuLink href="/about">À propos</SuLink>
<SuLink href="/contact">Contact</SuLink>
</SuLinkGroup>📱 Comportement responsive
Les séparateurs sont automatiquement masqués en mode vertical pour éviter l'encombrement visuel.
Comportement des props
🔄 Propagation automatique
Quand size, variant ou underline sont définies sur le LinkGroup, elles surchargent automatiquement les props des liens enfants :
<!-- Les liens auront TOUS la taille 'lg', la variante 'primary' et underline 'never' -->
<SuLinkGroup size="lg" variant="primary" underline="never">
<SuLink size="sm" variant="muted" underline="always" href="/link1">Lien 1</SuLink> <!-- Devient lg + primary + never -->
<SuLink href="/link2">Lien 2</SuLink> <!-- Devient lg + primary + never -->
<SuLink variant="secondary" href="/link3">Lien 3</SuLink> <!-- Devient lg + primary + never -->
</SuLinkGroup>🎯 Validation du contenu
Le composant vérifie automatiquement que seuls des composants Link sont passés dans le slot :
- ✅ Composants Link : Traités et stylés normalement
- ⚠️ Autres composants : Avertissement dans la console et élément ignoré
- ✅ Commentaires/texte : Ignorés silencieusement (comportement normal de Vue)
Espacement et bordures
📏 Valeurs de gap
gap="sm": 0.25rem (4px)gap="md": 0.5rem (8px) - défautgap="lg": 0.75rem (12px)gap="none": 0px avec bordures connectées
🔗 Gap "none" - Liens connectés
Quand gap="none", les liens sont visuellement connectés :
- Bordures superposées :
margin-left: -1pxpour éviter les bordures doubles - Border-radius adapté :
- Premier lien : coins gauches arrondis uniquement
- Liens du milieu : aucun coin arrondi
- Dernier lien : coins droits arrondis uniquement
- Lien unique : tous les coins arrondis
- Z-index intelligent : Focus, hover et active ont un z-index supérieur
Direction
📐 Horizontal vs Vertical
- Horizontal (défaut) : Liens alignés en ligne
- Vertical : Liens empilés en colonne
Pour gap="none" en mode vertical :
- Les marges deviennent
margin-top: -1px - Les border-radius s'adaptent (haut/bas au lieu de gauche/droite)
Accessibilité
Le composant LinkGroup respecte les normes WCAG 2.1 AA :
✅ Fonctionnalités d'accessibilité
- Rôles ARIA : Support des rôles
navigation,group, etc. - Labels de groupe :
aria-labelpour décrire le groupe - Navigation au clavier : Préserve la navigation Tab entre les liens
- Focus visible : Gestion du z-index pour la visibilité du focus
- Descriptions : Support d'
aria-describedbypour les descriptions
🎯 Bonnes pratiques
<!-- Navigation principale -->
<SuLinkGroup
gap="lg"
role="navigation"
aria-label="Navigation principale"
>
<SuLink href="/">Accueil</SuLink>
<SuLink href="/products">Produits</SuLink>
<SuLink href="/about">À propos</SuLink>
</SuLinkGroup>
<!-- Breadcrumb -->
<SuLinkGroup
gap="sm"
variant="muted"
size="sm"
separator="slash"
role="navigation"
aria-label="Fil d'ariane"
>
<SuLink href="/">Accueil</SuLink>
<SuLink href="/products">Produits</SuLink>
<SuLink href="/products/laptops">Ordinateurs portables</SuLink>
</SuLinkGroup>
<!-- Footer links -->
<SuLinkGroup gap="md" separator="dot" variant="secondary" aria-label="Liens du footer">
<SuLink href="/privacy">Confidentialité</SuLink>
<SuLink href="/terms">Conditions</SuLink>
<SuLink href="/contact">Contact</SuLink>
</SuLinkGroup>Exemples d'usage avancés
Navigation principale
<script setup>
import { HomeIcon, ShoppingBagIcon, InformationCircleIcon, PhoneIcon } from '@heroicons/vue/24/outline'
</script>
<template>
<header>
<nav role="navigation" aria-label="Navigation principale">
<SuLinkGroup gap="lg" variant="primary" size="md">
<SuLink href="/" :icon="HomeIcon" iconDisplay="left">
Accueil
</SuLink>
<SuLink href="/products" :icon="ShoppingBagIcon" iconDisplay="left">
Produits
</SuLink>
<SuLink href="/about" :icon="InformationCircleIcon" iconDisplay="left">
À propos
</SuLink>
<SuLink href="/contact" :icon="PhoneIcon" iconDisplay="left">
Contact
</SuLink>
</SuLinkGroup>
</nav>
</header>
</template>Sidebar de navigation
<script setup>
import {
ChartBarIcon,
DocumentTextIcon,
UsersIcon,
CogIcon
} from '@heroicons/vue/24/outline'
</script>
<template>
<aside>
<nav role="navigation" aria-label="Navigation latérale">
<SuLinkGroup
direction="vertical"
gap="sm"
variant="secondary"
size="md"
>
<SuLink to="/dashboard" :icon="ChartBarIcon" iconDisplay="left">
Tableau de bord
</SuLink>
<SuLink to="/reports" :icon="DocumentTextIcon" iconDisplay="left">
Rapports
</SuLink>
<SuLink to="/team" :icon="UsersIcon" iconDisplay="left">
Équipe
</SuLink>
<SuLink to="/settings" :icon="CogIcon" iconDisplay="left">
Paramètres
</SuLink>
</SuLinkGroup>
</nav>
</aside>
</template>Footer avec liens groupés
<template>
<footer>
<div class="footer-content">
<div class="footer-section">
<h4>Produit</h4>
<SuLinkGroup
direction="vertical"
gap="sm"
variant="muted"
size="sm"
underline="never"
>
<SuLink href="/features">Fonctionnalités</SuLink>
<SuLink href="/pricing">Tarifs</SuLink>
<SuLink href="/integrations">Intégrations</SuLink>
<SuLink href="/api">API</SuLink>
</SuLinkGroup>
</div>
<div class="footer-section">
<h4>Support</h4>
<SuLinkGroup
direction="vertical"
gap="sm"
variant="muted"
size="sm"
underline="never"
>
<SuLink href="/help">Centre d'aide</SuLink>
<SuLink href="/contact">Contact</SuLink>
<SuLink href="/status">Statut</SuLink>
<SuLink href="https://github.com/company" external>GitHub</SuLink>
</SuLinkGroup>
</div>
<div class="footer-section">
<h4>Légal</h4>
<SuLinkGroup
direction="vertical"
gap="sm"
variant="muted"
size="sm"
underline="never"
>
<SuLink href="/privacy">Confidentialité</SuLink>
<SuLink href="/terms">Conditions</SuLink>
<SuLink href="/cookies">Cookies</SuLink>
</SuLinkGroup>
</div>
</div>
</footer>
</template>
<style scoped>
.footer-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 2rem;
padding: 2rem;
background-color: #f9fafb;
}
.footer-section h4 {
margin-bottom: 1rem;
color: #374151;
font-weight: 600;
}
</style>Breadcrumb intelligent
<script setup>
import { computed } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const breadcrumbs = computed(() => {
const pathSegments = route.path.split('/').filter(Boolean)
const crumbs = [{ name: 'Accueil', path: '/' }]
let currentPath = ''
pathSegments.forEach(segment => {
currentPath += `/${segment}`
crumbs.push({
name: segment.charAt(0).toUpperCase() + segment.slice(1),
path: currentPath
})
})
return crumbs
})
</script>
<template>
<nav role="navigation" aria-label="Fil d'ariane">
<SuLinkGroup gap="sm" variant="muted" size="sm">
<template v-for="(crumb, index) in breadcrumbs" :key="crumb.path">
<SuLink
v-if="index < breadcrumbs.length - 1"
:to="crumb.path"
>
{{ crumb.name }}
</SuLink>
<span v-else style="color: #374151; font-weight: 500;">
{{ crumb.name }}
</span>
<span v-if="index < breadcrumbs.length - 1" style="color: #9ca3af; margin: 0 0.25rem;">
/
</span>
</template>
</SuLinkGroup>
</nav>
</template>Contrôle du contenu du slot
Le composant LinkGroup vérifie automatiquement le contenu de son slot :
✅ Éléments acceptés
- Composants
Linkdu design system - Commentaires Vue (ignorés)
- Nœuds de texte vides (ignorés)
⚠️ Éléments rejetés
- Autres composants ou éléments HTML
- Avertissement dans la console de développement
- Élément ignoré dans le rendu
🔍 Exemple de validation
<!-- ✅ Correct -->
<SuLinkGroup>
<SuLink href="/link1">Lien 1</SuLink>
<SuLink href="/link2">Lien 2</SuLink>
<!-- Commentaire ignoré -->
</SuLinkGroup>
<!-- ⚠️ Avertissement dans la console -->
<SuLinkGroup>
<SuLink href="/valid">Lien valide</SuLink>
<a href="/invalid">Élément non-Link</a> <!-- Ignoré avec avertissement -->
<SuLink href="/valid2">Autre lien valide</SuLink>
</SuLinkGroup>Cette approche garantit la cohérence visuelle tout en informant les développeurs des problèmes potentiels.