Skip to content

Contrôle segmenté - DsfrSegmentedSet

🌟 Bienvenue dans l'univers de DsfrSegmentedSet, le chef d'orchestre de vos composants radio boutonnés DsfrSegmented. Ce composant est là pour vous aider à organiser et afficher un ensemble de choix avec élégance et fonctionnalité. Préparez-vous, ça va être aussi sympa qu'une balade sur la Seine !

Le composant « contrôle segmenté » incite l'utilisateur à choisir entre plusieurs options d'affichage disponibles (vues), mutuellement exclusives avec une valeur sélectionnée par défaut (Il faut toujours ramener un peu de sérieux dans l’affaire...).

🏅 La documentation sur les boutons segmentés sur le DSFR sera ici (n’existe pas non plus à l’heure où cette documentation est écrite, on est trop en avance, nous !).

La story sur l’alerte sur le storybook de VueDsfr est ici (oui parce que nous on fait rien à moitié, nous 😏, merci Vincent Lainé !).

🛠️ Props

NomTypeDéfautObligatoireDescription
titleIdstringID aléatoireIdentifiant unique pour le titre du groupe.
disabledbooleanfalseSi true, désactive tous les boutons radio du groupe.
smallbooleanfalseSi true, Utilise la version réduite des contrôles segmentés.
inlinebooleanfalseSi true, la légende sera alignée avec les boutons, sinon, ils seront chacun sur une ligne (false, défaut).
namestring'no-name'Nom par défaut pour le groupe de boutons radio.
hintstringundefinedTexte d'indice affiché sous la légende (facultatif).
legendstring''Texte de la légende pour le groupe de boutons radio.
modelValuestring | numberLa valeur actuellement sélectionnée.
optionsDsfrSegmentedProps[][]Tableau d’objets : chaque objet contient les props à passer à DsfrSegmented.

Notes

  • titleId: Généré automatiquement si non spécifié.
  • options: Chaque élément représente un bouton radio avec ses props spécifiques.

📡 Événements

NomValeurDescription
update:modelValuestring | numberÉmis lorsqu'une nouvelle valeur est sélectionnée dans le groupe.

🧩 Slots

  1. slot par défaut: Permet de personnaliser les boutons radio individuellement.
  2. Slot legend: Permet de personnaliser la légende avec du contenu riche.

📝 Exemple

vue
<DsfrSegmentedSet
  legend="Votre Choix"
  :options="[
    {
      label: 'Croissant',
      value: 'croissant',
    },
    {
      label: 'Pain au chocolat (noooon ! Cho-co-la-tine ! C’est pas compliqué, pourtant !)',
      value: 'chocolatine',
      disabled: true,
    }
  ]"
  v-model="selectedOption"
/>

Assurez-vous d'importer DsfrSegmentedSet ainsi que DsfrSegmented dans votre projet. Puis, utilisez-le dans votre template en fournissant les props et les options nécessaires.

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

import DsfrSegmented from '../DsfrSegmented.vue'
import DsfrSegmentedSet from '../DsfrSegmentedSet.vue'

const region = ref<string | number>('')
const viennoiserie = ref<string | number>('')

const options = [
  { label: 'Sud-ouest', value: 'Chocolatine' },
  { label: 'Ailleurs', value: 'Pain au chocolat' },
]
</script>

<template>
  <div class="fr-container">
    <div>
      <DsfrSegmentedSet
        name="region"
        label="Région"
        :options="options"
        @update:model-value="region = $event"
      />
    </div>

    <div
      v-if="region"
      class="fr-mt-4w"
    >
      <DsfrSegmentedSet
        name="viennoiserie"
        label="Viennoiserie"
      >
        <DsfrSegmented
          icon="fr-icon-moon-line"
          label="Croissant"
          value="croissant"
          :model-value="viennoiserie"
          @update:model-value="viennoiserie = $event"
        />
        <DsfrSegmented
          :label="region.toString()"
          value="chocolatine"
          :icon="{ name: 'gi-chocolate-bar' }"
          :model-value="viennoiserie"
          @update:model-value="viennoiserie = $event"
        />
      </DsfrSegmentedSet>
      <p>
        Vrai nom : {{ viennoiserie }}
      </p>
    </div>
  </div>
</template>

⚙️ Code source du composant

vue
<script lang="ts" setup>
import DsfrSegmented from './DsfrSegmented.vue'
import { getRandomId } from '../../utils/random-utils'

import type { DsfrSegmentedSetProps } from './DsfrSegmented.types'

export type { DsfrSegmentedSetProps }

const props = withDefaults(defineProps<DsfrSegmentedSetProps>(), {
  titleId: () => getRandomId('radio-button', 'group'),
  legend: '',
  name: 'no-name',
  options: () => [],
})

const emit = defineEmits<{ (e: 'update:modelValue', payload: string | number): void }>()

const onChange = ($event: string) => {
  if ($event === props.modelValue) {
    return
  }
  emit('update:modelValue', $event)
}
</script>

<template>
  <div class="fr-form-group">
    <fieldset
      class="fr-segmented"
      :class="{
        'fr-segmented--sm': small,
        'fr-segmented--no-legend': !legend,
      }"
      :disabled="disabled"
    >
      <legend
        v-if="legend"
        :id="titleId"
        class="fr-segmented__legend"
        :class="{
          'fr-segmented__legend--inline': inline,
        }"
      >
        <!-- @slot Slot pour personnaliser tout le contenu de la balise <legend> cf. [DsfrInput](/?path=/story/composants-champ-de-saisie-champ-simple-dsfrinput--champ-avec-label-personnalise). Une **props porte le même nom pour une légende simple** (texte sans mise en forme) -->
        <slot name="legend">
          {{ legend }}
        </slot>
        <span
          v-if="hint"
          class="fr-hint-text"
        >
          {{ hint }}
        </span>
      </legend>

      <div class="fr-segmented__elements">
        <slot>
          <DsfrSegmented
            v-for="(option, i) of options"
            :key="option.value || i"
            :name="name || option.name"
            v-bind="{ ...option, disabled: disabled || option.disabled }"
            :model-value="modelValue"
            @update:model-value="onChange($event as string)"
          />
        </slot>
      </div>
    </fieldset>
  </div>
</template>
ts
import type { OhVueIcon as VIcon } from 'oh-vue-icons'

export type DsfrSegmentedProps = {
  id?: string
  name?: string
  modelValue?: string | number
  value: string | number
  label: string
  disabled?: boolean
  icon?: string | InstanceType<typeof VIcon>['$props']
}

export type DsfrSegmentedSetProps = {
  titleId?: string
  disabled?: boolean
  small?: boolean
  inline?: boolean
  name?: string
  hint?: string
  legend?: string
  modelValue: string | number
  options?: DsfrSegmentedProps[]
}