Pictogramme - DsfrPictogram
🌟 Introduction
Le pictogramme est une illustration décorative du DSFR. Il est livré sous forme de SVG en trois calques (artwork-decorative, artwork-minor et artwork-major) qui prennent les couleurs du thème courant, clair ou sombre.
Le composant DsfrPictogram affiche ces pictogrammes partout où vous en avez besoin, sans passer par une tuile ou un bouton radio riche. Il choisit seul la façon de rendre le SVG selon ce que vous lui donnez, ce qui évite un piège courant : un pictogramme importé par un bundler arrive souvent sous forme de data URI, et une balise use ne sait pas référencer un fragment dans une data URI.
🏅 La documentation sur les pictogrammes sur le DSFR
La story sur le pictogramme sur le storybook de VueDsfr📐 Structure
Le composant rend, selon les props reçues :
- une balise
imgportant la classefr-artworksiimgSrcest renseignée ; - le SVG en ligne, nettoyé de son contenu actif, si
svgPathest une data URI exploitable ; les identifiants des calques y sont suffixés pour que deux pictogrammes de la même page restent indépendants ; - une balise
imgsisvgPathest une data URI qui n’a pas pu être analysée ; - une balise
svgréférençant les trois calques du pictogramme dans les autres cas.
Sans imgSrc ni svgPath, le composant ne rend rien.
🛠️ Props
| Nom | Type | Description | Valeur par défaut | Obligatoire |
|---|---|---|---|---|
imgSrc | string | Source de l’image à afficher, prioritaire sur svgPath. | undefined | |
svgPath | string | Chemin du pictogramme SVG, tel qu’importé depuis @gouvfr/dsfr/dist/artwork/pictograms. | undefined | |
svgAttrs | Record<string, unknown> | Attributs à poser sur la balise svg, fusionnés avec les valeurs par défaut. | { viewBox: '0 0 80 80', width: '80px', height: '80px' } | |
title | string | Titre du pictogramme, à ne renseigner que s’il porte une information absente du texte environnant. | undefined |
📡 Événements
Ce composant ne déclenche pas d’événements spécifiques.
🧩 Slots
Ce composant n’a pas de slot.
♿ Accessibilité
Un pictogramme est une illustration : il est masqué aux technologies d’assistance (aria-hidden sur les SVG, alternative vide sur les images). Ne renseignez title que si le pictogramme porte une information absente du texte qui l’entoure.
📝 Exemples
<script lang="ts" setup>
import svgSchool from '@gouvfr/dsfr/dist/artwork/pictograms/buildings/school.svg'
</script>
<template>
<DsfrPictogram :svg-path="svgSchool" />
</template><template>
<DsfrPictogram
:svg-path="svgSchool"
:svg-attrs="{ width: '40px', height: '40px' }"
/>
</template><script lang="ts" setup>
import svgCityHall from '@gouvfr/dsfr/dist/artwork/pictograms/buildings/city-hall.svg'
import svgSchool from '@gouvfr/dsfr/dist/artwork/pictograms/buildings/school.svg'
import svgContract from '@gouvfr/dsfr/dist/artwork/pictograms/document/contract.svg'
import { ref } from 'vue'
import DsfrButton from '../../DsfrButton/DsfrButton.vue'
import DsfrPictogram from '../DsfrPictogram.vue'
const pictograms = [svgSchool, svgCityHall, svgContract]
const currentIndex = ref(0)
const svgPath = ref(pictograms[0])
function nextPictogram () {
currentIndex.value = (currentIndex.value + 1) % pictograms.length
svgPath.value = pictograms[currentIndex.value]
}
</script>
<template>
<div class="demo-container-col">
<div class="flex items-center gap-4">
<DsfrPictogram :svg-path="svgPath" />
<DsfrPictogram
:svg-path="svgPath"
:svg-attrs="{ width: '40px', height: '40px' }"
/>
<DsfrPictogram
:svg-path="svgPath"
:svg-attrs="{ width: '24px', height: '24px' }"
/>
</div>
<DsfrButton
label="Changer de pictogramme"
@click="nextPictogram()"
/>
</div>
</template>⚙️ Code source du composant
<script lang="ts" setup>
import type { DsfrPictogramProps } from './DsfrPictogram.types'
import { computed } from 'vue'
import { useRandomId } from '../../utils/random-utils'
import { sanitizeInlineSvgMarkupFromDataUri } from '../../utils/svg-data-uri-utils'
export type { DsfrPictogramProps }
const props = withDefaults(defineProps<DsfrPictogramProps>(), {
imgSrc: undefined,
svgPath: undefined,
svgAttrs: () => ({ viewBox: '0 0 80 80', width: '80px', height: '80px' }),
title: undefined,
})
const dataImageRegex = /^data:image\/svg\+xml(?:;[^,]*)?,/i
const defaultSvgAttrs = { viewBox: '0 0 80 80', width: '80px', height: '80px' }
const inlineSvgIdSuffix = useRandomId('pictogram', 'artwork').replace(/[^\w-]/g, '_')
const svgDataUriComputed = computed(() => !!props.svgPath?.match(dataImageRegex))
const svgDataUriMarkupComputed = computed(() => (
sanitizeInlineSvgMarkupFromDataUri(props.svgPath, inlineSvgIdSuffix)
))
</script>
<template>
<img
v-if="imgSrc"
:src="imgSrc"
class="fr-artwork"
alt=""
:title="title"
>
<span
v-else-if="svgDataUriMarkupComputed"
aria-hidden="true"
class="fr-artwork fr-artwork--inline"
v-html="svgDataUriMarkupComputed"
/>
<img
v-else-if="svgDataUriComputed"
:src="svgPath"
class="fr-artwork"
alt=""
:title="title"
>
<svg
v-else-if="svgPath"
aria-hidden="true"
class="fr-artwork"
v-bind="{ ...defaultSvgAttrs, ...svgAttrs }"
>
<title v-if="title">{{ title }}</title>
<use
class="fr-artwork-decorative"
:href="`${svgPath}#artwork-decorative`"
/>
<use
class="fr-artwork-minor"
:href="`${svgPath}#artwork-minor`"
/>
<use
class="fr-artwork-major"
:href="`${svgPath}#artwork-major`"
/>
</svg>
</template>
<style scoped>
.fr-artwork--inline :deep(svg) {
width: 100%;
height: 100%;
}
</style>export type DsfrPictogramProps = {
/**
* Chemin d’une image matricielle (ou d’un SVG à afficher tel quel) à utiliser comme pictogramme
*/
imgSrc?: string
/**
* Chemin du pictogramme SVG, tel qu’importé depuis `@gouvfr/dsfr/dist/artwork/pictograms`
*/
svgPath?: string
/**
* Attributs à poser sur la balise `svg` (`viewBox`, `width` et `height` par défaut)
*/
svgAttrs?: Record<string, unknown>
/**
* Titre du pictogramme, à ne renseigner que s’il porte une information absente du texte environnant
*/
title?: string
}