Skip to content

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

vue
<template>
  <SuLinkGroup>
    <SuLink href="/home">Accueil</SuLink>
    <SuLink href="/about">À propos</SuLink>
    <SuLink href="/contact">Contact</SuLink>
  </SuLinkGroup>
</template>

Espacement (gap)

Différents espacements

Gap Small

Gap Medium (défaut)

Gap Large

Gap None (connecté)

vue
<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

Taille Small forcée

Taille Medium forcée

Taille Large forcée

vue
<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

Variante Primary forcée

Variante Secondary forcée

Variante Muted forcée

vue
<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

Séparateur point (•)

Séparateur slash (/)

Séparateur pipe (|)

Séparateur flèche (→)

vue
<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

vue
<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

Primary connecté

Secondary connecté

Navigation d'icônes

vue
<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

PropTypeDefaultDescription
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'undefinedTaille forcée pour tous les liens
variant'default' | 'primary' | 'secondary' | 'muted'undefinedVariante forcée pour tous les liens
underline'always' | 'hover' | 'never'undefinedSoulignement forcé pour tous les liens
direction'horizontal' | 'vertical''horizontal'Direction du groupe

Attributs d'accessibilité

PropTypeDefaultDescription
ariaLabelstringundefinedLabel accessible pour le groupe
ariaDescribedBystringundefinedID de l'élément de description
rolestringundefinedRôle ARIA personnalisé (ex: 'navigation', 'group')

Slots

SlotDescription
defaultLiens à 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 (→)
vue
<!-- 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 :

vue
<!-- 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éfaut
  • gap="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: -1px pour é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-label pour 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-describedby pour les descriptions

🎯 Bonnes pratiques

vue
<!-- 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

vue
<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>
vue
<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>
vue
<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>
vue
<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 Link du 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

vue
<!-- ✅ 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.

Publié sous licence MIT.