Skip to content

Tag - DsfrTag

🌟 Introduction

Le tag catégorise/classe/organise les contenus à l'aide de mots-clés. Il aide les utilisateurs à rechercher et à trouver facilement une information.

Le tag peut être utilisé dans deux contextes :

  • Dans le contenu (carte, en-tête, liste) : il catégorise le contenu auquel il est apposé. Il peut être cliquable ou non cliquable ;

  • En tant que filtre (dans une page de résultats de recherche par exemple). Dans ce cas il peut-être :

    • activable comme filtre en place à sélectionner/désélectionner ;
    • supprimable, il sert de rappel à un filtre qui a été coché dans une sidebar ou une liste déroulante.

🏅 La documentation sur le tag sur le DSFR

La story sur le tag sur le storybook de VueDsfr

📐 Structure

Il se compose des éléments suivants :

  • un libellé obligatoire : soit en utilisant la prop label soit en utilisant le slot par défaut ;
  • une icône optionnelle : avec la prop icon qui peut être soit le nom d’une classe correspondant à une icône du DSFR (elle commence par 'fr-icon-'), soit le nom d’une icône de @iconify/vue, cf. la documentation sur les icônes) et celle du composant VIcon.

🛠️ Props

NomTypeDéfautObligatoireDescription
labelStringundefinedLe texte affiché sur l'étiquette.
linkStringundefinedURL pour un lien externe. Détermine aussi le type de balise (a ou RouterLink).
tagNameString'p'Nom de la balise utilisée pour l'étiquette.
iconStringundefinedNom de l'icône (@iconify/vue) à afficher sur l'étiquette.
disabledBooleanfalseDésactive l'étiquette si elle est un bouton.
smallBooleanfalseRéduit la taille de l'étiquette.
iconOnlyBooleanfalseAffiche uniquement l'icône, sans texte.

📡 Évenements

Pas d'événements personnalisés pour ce composant. Il se repose sur les événements natifs de ses balises sous-jacentes.

🧩 Slots

NomDescription
defaultSlot par défaut pour ajouter du contenu supplémentaire à côté du label ou de l'icône.

📝 Exemples

vue
<script lang="ts" setup>
import DsfrTag from '@/components/DsfrTag/DsfrTag.vue'
</script>

<template>
  <div class="flex  gap-2  fr-m-2v  flex-wrap">
    <DsfrTag
      label="Vue Power"
    />
    <DsfrTag
      label="DSFR"
      icon="fr-icon-success-line"
    />
    <DsfrTag
      label="Iconify Power"
      icon="ri-bell-line"
    />
    <DsfrTag
      label="Tag inactif (disabled)"
      icon="ri-stop-line"
      title="désactivé"
      disabled
    />
    <DsfrTag
      label="Icône seule"
      title="Icône seule"
      icon="ri-play-line"
      icon-only
    />
    <DsfrTag
      label="Petit tag"
      title="Petite"
      small
    />
    <DsfrTag
      label="Petit tag avec icone DSFR"
      title="Petite"
      small
      icon="fr-icon-success-line"
    />
    <DsfrTag
      label="Petit tag avec icone Iconify"
      title="Petite"
      small
      icon="ri-checkbox-circle-line"
    />
  </div>
</template>

⚙️ Code source du composant

vue
<script lang="ts" setup>
import { computed } from 'vue'

import VIcon from '../VIcon/VIcon.vue'

import type { DsfrTagProps } from './DsfrTags.types'

export type { DsfrTagProps }

const props = withDefaults(defineProps<DsfrTagProps>(), {
  label: undefined,
  link: undefined,
  tagName: 'p',
  icon: undefined,
})

const isExternalLink = computed(() => typeof props.link === 'string' && props.link.startsWith('http'))
const is = computed(() => {
  return props.link
    ? (isExternalLink.value ? 'a' : 'RouterLink')
    : ((props.disabled && props.tagName === 'p') ? 'button' : props.tagName)
})
const linkProps = computed(() => {
  return { [isExternalLink.value ? 'href' : 'to']: props.link }
})

const dsfrIcon = computed(() => typeof props.icon === 'string' && props.icon.startsWith('fr-icon-'))
const defaultScale = props.small ? 0.65 : 0.9
const iconProps = computed(() => dsfrIcon.value ? undefined : typeof props.icon === 'string' ? { name: props.icon, scale: defaultScale } : { scale: defaultScale, ...(props.icon ?? {}) })
</script>

<template>
  <component
    :is="is"
    class="fr-tag"
    :disabled="disabled"
    :class="{
      'fr-tag--sm': small,
      [icon as string]: dsfrIcon,
      'fr-tag--icon-left': dsfrIcon,
    }"
    v-bind="linkProps"
  >
    <VIcon
      v-if="props.icon && !dsfrIcon"
      :label="iconOnly ? label : undefined"
      class="fr-mr-1v"
      v-bind="iconProps"
    />
    <template v-if="!iconOnly">
      {{ label }}
    </template>
    <!-- @slot Slot par défaut pour le contenu du tag -->
    <slot />
  </component>
</template>

<style scoped>
.ov-icon {
  margin-top: 0.1rem;
}

.fr-tag {
  align-items: center;
}

.success {
  color: var(--success);
  background-color: var(--bg-success);
}
.error {
  color: var(--error);
  background-color: var(--bg-error);
}
.warning {
  color: var(--warning);
  background-color: var(--bg-warning);
}
.info {
  color: var(--info);
  background-color: var(--bg-info);
}
</style>
ts
export type DsfrTagProps = {
  label?: string
  link?: string
  tagName?: string
  icon?: string
  disabled?: boolean
  small?: boolean
  iconOnly?: boolean
}

export type DsfrTagsProps = {
  tags: DsfrTagProps[]
}