Skip to content

Badge

Composant Badge moderne et minimaliste pour afficher des informations courtes, des statuts ou des notifications. Support des icônes, variantes dot et accessibilité complète selon les normes W3C.

Exemples d'utilisation

Badge de base

Badge simple

vue
<template>
  <SuBadge>Badge par défaut</SuBadge>
  <SuBadge variant="primary">Primary</SuBadge>
  <SuBadge variant="success">Success</SuBadge>
</template>

Variantes

Variantes disponibles

vue
<template>
  <SuBadge variant="default">Default</SuBadge>
  <SuBadge variant="primary">Primary</SuBadge>
  <SuBadge variant="secondary">Secondary</SuBadge>
  <SuBadge variant="success">Success</SuBadge>
  <SuBadge variant="warning">Warning</SuBadge>
  <SuBadge variant="error">Error</SuBadge>
</template>

Tailles

Tailles disponibles

vue
<template>
  <SuBadge size="sm">Small</SuBadge>
  <SuBadge size="md">Medium</SuBadge>
  <SuBadge size="lg">Large</SuBadge>
</template>

Rayons de bordure

Rayons de bordure disponibles

vue
<template>
  <SuBadge radius="none">None</SuBadge>
  <SuBadge radius="sm">Small</SuBadge>
  <SuBadge radius="md">Medium</SuBadge>
  <SuBadge radius="lg">Large</SuBadge>
  <SuBadge radius="xl">Extra Large</SuBadge>
  <SuBadge radius="max">Full</SuBadge>
</template>

Avec icônes

Badges avec icônes

vue
<script setup>
import { CheckIcon, XMarkIcon, ExclamationTriangleIcon, StarIcon } from '@heroicons/vue/24/outline'
</script>

<template>
  <SuBadge variant="success" icon="CheckIcon" iconDisplay="left">Validé</SuBadge>
  <SuBadge variant="error" icon="XMarkIcon" iconDisplay="left">Erreur</SuBadge>
  <SuBadge variant="warning" icon="ExclamationTriangleIcon" iconDisplay="left">Attention</SuBadge>
  <SuBadge variant="primary" icon="StarIcon" iconDisplay="right">Premium</SuBadge>
</template>

Icônes seules

Badges avec icônes uniquement

vue
<script setup>
import { CheckIcon, XMarkIcon, ExclamationTriangleIcon, StarIcon } from '@heroicons/vue/24/outline'
</script>

<template>
  <!-- Icônes seules (OBLIGATOIRE: aria-label) -->
  <SuBadge variant="success" icon="CheckIcon" iconDisplay="only" aria-label="Validé" />
  <SuBadge variant="error" icon="XMarkIcon" iconDisplay="only" aria-label="Erreur" />
  <SuBadge variant="warning" icon="ExclamationTriangleIcon" iconDisplay="only" aria-label="Attention" />
  <SuBadge variant="primary" icon="StarIcon" iconDisplay="only" aria-label="Premium" />
</template>

Variante dot

Dots simples

vue
<template>
  <!-- Dot simple -->
  <SuBadge variant="dot" />
  
  <!-- Dots avec couleurs personnalisées -->
  <SuBadge variant="dot" backgroundColor="#10b981" />
  <SuBadge variant="dot" backgroundColor="#f59e0b" />
  <SuBadge variant="dot" backgroundColor="#ef4444" />
</template>

Dots avec texte

Dots avec texte

vue
<template>
  <SuBadge variant="dot" dotText="En ligne" backgroundColor="#10b981" />
  <SuBadge variant="dot" dotText="Absent" backgroundColor="#f59e0b" />
  <SuBadge variant="dot" dotText="Occupé" backgroundColor="#ef4444" />
  <SuBadge variant="dot" dotText="Hors ligne" backgroundColor="#6b7280" />
</template>

Couleurs personnalisées

Couleurs personnalisées

vue
<template>
  <SuBadge backgroundColor="#8b5cf6" color="white">Violet</SuBadge>
  <SuBadge backgroundColor="#ec4899" color="white">Rose</SuBadge>
  <SuBadge backgroundColor="#06b6d4" color="white">Cyan</SuBadge>
  <SuBadge backgroundColor="#84cc16" color="white">Lime</SuBadge>
</template>

API

Props

PropTypeDefaultDescription
variant'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'dot''default'Variante visuelle du badge
size'sm' | 'md' | 'lg''md'Taille du badge
radius'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full''md'Rayon de bordure du badge
iconComponentundefinedIcône à afficher
iconDisplay'left' | 'right' | 'only''left'Position de l'icône
dotTextstringundefinedTexte affiché à côté du dot (variante dot uniquement)
colorstringundefinedCouleur personnalisée du texte
backgroundColorstringundefinedCouleur personnalisée de l'arrière-plan

Attributs d'accessibilité

PropTypeDefaultDescription
ariaLabelstringundefinedLabel accessible
ariaDescribedBystringundefinedID de l'élément de description
ariaHiddenbooleanundefinedMasquer aux lecteurs d'écran
rolestringundefinedRôle ARIA personnalisé

Slots

SlotDescription
defaultContenu du badge

Variante dot

La variante dot est spéciale et offre deux modes d'affichage :

🔴 Dot simple

Un simple point coloré, idéal pour les indicateurs de statut :

vue
<!-- Dot par défaut -->
<SuBadge variant="dot" />

<!-- Dot avec couleur personnalisée -->
<SuBadge variant="dot" backgroundColor="#10b981" />

🔴 Dot avec texte

Un point coloré suivi d'un texte, parfait pour les statuts avec description :

vue
<!-- Avec prop dotText -->
<SuBadge variant="dot" dotText="En ligne" backgroundColor="#10b981" />

<!-- Avec slot -->
<SuBadge variant="dot" backgroundColor="#f59e0b">
  Absent depuis 5 min
</SuBadge>

Accessibilité

Le composant Badge respecte les normes WCAG 2.1 AA :

✅ Fonctionnalités d'accessibilité

  • Contraste des couleurs : Ratios de contraste conformes WCAG AA (4.5:1 minimum)
  • Attributs ARIA : Support complet des attributs ARIA
  • Icônes accessibles : Icônes marquées avec aria-hidden="true"
  • Labels appropriés : Support d'aria-label pour les badges informatifs
  • Mode sombre : Contraste adapté automatiquement
  • Contraste élevé : Support de prefers-contrast: high
  • Couleurs personnalisées : Calcul automatique du contraste pour les couleurs custom

🎯 Bonnes pratiques

vue
<!-- Badge avec icône seule (OBLIGATOIRE: aria-label) -->
<SuBadge variant="success" icon="CheckIcon" iconDisplay="only" aria-label="Statut validé" />

<!-- Badge informatif -->
<SuBadge variant="primary" aria-label="Utilisateur premium">Premium</SuBadge>

<!-- Badge décoratif (masqué aux lecteurs d'écran) -->
<SuBadge variant="dot" backgroundColor="#10b981" aria-hidden="true" />

<!-- Badge avec description -->
<SuBadge variant="warning" aria-describedby="warning-description">
  Attention
</SuBadge>
<div id="warning-description">Cette action nécessite une confirmation</div>

Exemples d'usage

États de commande

vue
<script setup>
import { CheckIcon, ClockIcon, XMarkIcon, TruckIcon } from '@heroicons/vue/24/outline'
</script>

<template>
  <div class="order-status">
    <SuBadge variant="success" icon="CheckIcon" iconDisplay="left" radius="max">
      Livré
    </SuBadge>
    <SuBadge variant="warning" icon="TruckIcon" iconDisplay="left" radius="max">
      En transit
    </SuBadge>
    <SuBadge variant="default" icon="ClockIcon" iconDisplay="left" radius="max">
      En préparation
    </SuBadge>
    <SuBadge variant="error" icon="XMarkIcon" iconDisplay="left" radius="max">
      Annulé
    </SuBadge>
  </div>
</template>

Notifications

vue
<template>
  <div class="notifications">
    <!-- Compteurs de notifications -->
    <div class="notification-item">
      <span>Messages</span>
      <SuBadge variant="error" radius="max" size="sm">3</SuBadge>
    </div>
    
    <div class="notification-item">
      <span>Notifications</span>
      <SuBadge variant="warning" radius="max" size="sm">12</SuBadge>
    </div>
    
    <div class="notification-item">
      <span>Mises à jour</span>
      <SuBadge variant="success" radius="max" size="sm">99+</SuBadge>
    </div>
  </div>
</template>

<style scoped>
.notification-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.75rem;
  background-color: #f9fafb;
  border-radius: 0.5rem;
  margin-bottom: 0.5rem;
}
</style>

Statuts utilisateur

vue
<template>
  <div class="user-list">
    <div class="user-item">
      <div class="user-info">
        <div class="user-avatar">JD</div>
        <span>John Doe</span>
      </div>
      <div class="user-status">
        <SuBadge variant="dot" dotText="En ligne" backgroundColor="#10b981" />
        <SuBadge variant="primary" size="sm" icon="StarIcon" iconDisplay="only" aria-label="Utilisateur premium" />
      </div>
    </div>
    
    <div class="user-item">
      <div class="user-info">
        <div class="user-avatar">MD</div>
        <span>Marie Dupont</span>
      </div>
      <div class="user-status">
        <SuBadge variant="dot" dotText="Absent" backgroundColor="#f59e0b" />
        <SuBadge variant="secondary" size="sm">Admin</SuBadge>
      </div>
    </div>
  </div>
</template>

<style scoped>
.user-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem;
  background-color: white;
  border-radius: 0.5rem;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  margin-bottom: 0.75rem;
}

.user-info {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.user-avatar {
  width: 2.5rem;
  height: 2.5rem;
  background-color: #3b82f6;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-weight: 600;
}

.user-status {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
</style>

Étiquettes de produit

vue
<template>
  <div class="product-card">
    <div class="product-header">
      <h3>MacBook Pro</h3>
      <SuBadge variant="success" size="sm" radius="max">En stock</SuBadge>
    </div>
    
    <p class="product-description">
      Ordinateur portable haute performance
    </p>
    
    <div class="product-tags">
      <SuBadge variant="primary" size="sm" radius="max">Nouveau</SuBadge>
      <SuBadge variant="warning" size="sm" radius="max">Promo -20%</SuBadge>
      <SuBadge variant="default" size="sm" radius="max">13"</SuBadge>
      <SuBadge variant="secondary" size="sm" radius="max">M3</SuBadge>
    </div>
  </div>
</template>

<style scoped>
.product-card {
  padding: 1.5rem;
  background-color: white;
  border-radius: 0.75rem;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  max-width: 300px;
}

.product-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 1rem;
}

.product-header h3 {
  margin: 0;
  font-size: 1.125rem;
  font-weight: 600;
}

.product-description {
  margin: 0 0 1rem 0;
  color: #6b7280;
  font-size: 0.875rem;
}

.product-tags {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}
</style>

Indicateurs de statut de service

vue
<template>
  <div class="service-status">
    <h3>État des services</h3>
    
    <div class="status-list">
      <div class="status-item">
        <span>API Principal</span>
        <SuBadge variant="dot" dotText="Opérationnel" backgroundColor="#10b981" />
      </div>
      
      <div class="status-item">
        <span>Base de données</span>
        <SuBadge variant="dot" dotText="Dégradé" backgroundColor="#f59e0b" />
      </div>
      
      <div class="status-item">
        <span>CDN</span>
        <SuBadge variant="dot" dotText="Panne" backgroundColor="#ef4444" />
      </div>
      
      <div class="status-item">
        <span>Authentification</span>
        <SuBadge variant="dot" dotText="Maintenance" backgroundColor="#3b82f6" />
      </div>
    </div>
  </div>
</template>

<style scoped>
.service-status {
  max-width: 400px;
  padding: 1.5rem;
  background-color: white;
  border-radius: 0.75rem;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.service-status h3 {
  margin: 0 0 1.5rem 0;
  color: #1f2937;
}

.status-list {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.status-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.75rem;
  background-color: #f9fafb;
  border-radius: 0.5rem;
}
</style>

Badges cliquables

vue
<script setup>
import { StarIcon, CheckIcon } from '@heroicons/vue/24/outline'

const handleBadgeClick = (type) => {
  console.log(`Badge ${type} cliqué!`)
}
</script>

<template>
  <div class="clickable-badges">
    <h4>Badges interactifs</h4>
    
    <div class="badge-buttons">
      <button 
        @click="handleBadgeClick('premium')"
        class="badge-button"
      >
        <SuBadge variant="primary" icon="StarIcon" iconDisplay="left" radius="max">
          Premium
        </SuBadge>
      </button>
      
      <button 
        @click="handleBadgeClick('verified')"
        class="badge-button"
      >
        <SuBadge variant="success" icon="CheckIcon" iconDisplay="left" radius="max">
          Vérifié
        </SuBadge>
      </button>
    </div>
  </div>
</template>

<style scoped>
.badge-buttons {
  display: flex;
  gap: 1rem;
  margin-top: 1rem;
}

.badge-button {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  transition: transform 0.2s;
}

.badge-button:hover {
  transform: scale(1.05);
}

.badge-button:active {
  transform: scale(0.95);
}
</style>

Cas d'usage courants

🏷️ Étiquettes et catégories

  • Produits : Nouveau, Promo, En stock, Rupture
  • Articles : Publié, Brouillon, Archivé
  • Projets : Actif, Terminé, En pause

📊 Statuts et états

  • Utilisateurs : En ligne, Absent, Occupé, Hors ligne
  • Services : Opérationnel, Dégradé, Panne, Maintenance
  • Commandes : Confirmé, Expédié, Livré, Annulé

🔔 Notifications et compteurs

  • Messages : Nombre de messages non lus
  • Alertes : Nombre d'alertes actives
  • Mises à jour : Nouvelles fonctionnalités disponibles

⭐ Niveaux et récompenses

  • Utilisateurs : Débutant, Intermédiaire, Expert
  • Abonnements : Gratuit, Premium, Enterprise
  • Réalisations : Badges de progression, certifications

Bonnes pratiques

✅ À faire

  • Utiliser des couleurs cohérentes pour les mêmes types de statut
  • Fournir un aria-label pour les badges avec icône seule
  • Utiliser la variante dot pour les indicateurs de statut discrets
  • Limiter le texte à quelques mots maximum
  • Utiliser radius="max" pour les compteurs de notifications

❌ À éviter

  • Utiliser trop de badges dans une même interface
  • Mettre des textes longs dans les badges
  • Oublier l'accessibilité pour les badges informatifs
  • Utiliser des couleurs sans signification cohérente
  • Surcharger visuellement avec trop de variantes différentes

Performance

🚀 Optimisations intégrées

  • CSS minimal : Styles optimisés et légers
  • Pas de JavaScript : Composant purement CSS (sauf calcul de contraste)
  • Transitions fluides : Animations hardware-accelerated
  • Mode sombre : Support natif sans JavaScript

📊 Impact minimal

  • CSS généré : ~2KB gzippé
  • Rendu : Aucun impact sur les performances
  • Accessibilité : Aucun compromis sur les performances
  • Responsive : Adaptation automatique

Publié sous licence MIT.