Skip to content

Composant DsfrNewsLetter

🌟 Introduction

Le composant DsfrNewsLetter est conçu pour afficher un formulaire d'inscription à une lettre d'information (newsletter). Pour avoir un style conforme au Design System de l'État Français (DSFR) il doit être impérativement être appelé par le composant DsfrFollow. Flexible et accessible, il s'adapte à différents cas d'usage grâce à ses props personnalisables.

🏅 La documentation sur la lettre d’information sur le DSFR

La story sur la lettre d’information sur le storybook de VueDsfr

📐 Structure

Le composant offre deux modes :

  • Mode callout : un simple bouton pour l'inscription à la newsletter.
  • Mode formulaire : un formulaire complet avec champ email, bouton de soumission, et gestion des erreurs.

🛠️ Props

NomTypeDéfautDescription
titlestring'Abonnez-vous à notre lettre d’information'Titre affiché en haut de la section newsletter.
descriptionstring''Texte descriptif affiché sous le titre.
emailstring''Valeur initiale du champ email.
errorstring''Message d'erreur à afficher si la saisie est invalide.
labelEmailstring'Votre adresse électronique (ex. : prenom.nom@example.com)'Label du champ email.
placeholderstring'prenom.nom@example.com'Texte de placeholder pour le champ email.
hintTextstring''Texte d'aide affiché sous le champ email.
inputTitlestring'Adresse courriel'Titre de l'input email (pour l'attribut title de l'élément HTML).
buttonTextstring'S’abonner'Texte du bouton de soumission.
buttonTitlestring'S’abonner à notre lettre d’information'Titre du bouton (pour l'attribut title de l'élément HTML).
buttonAction($event: MouseEvent) => void() => undefinedAction personnalisée exécutée au clic du bouton en mode callout.
onlyCalloutbooleanfalseActive le mode "callout" avec un simple bouton au lieu du formulaire complet.

📡Événements

NomPayloadDescription
update:emailstringÉmis lorsque l'utilisateur modifie le champ email.

🧩 Slots

Aucun slot disponible pour ce composant.

📝 Exemples

Exemple de base

vue
<DsfrNewsLetter
        email="prenom.nom@example.com"
        title="Abonnez-vous à notre lettre d’information"
        label-email="Votre adresse électronique (ex. : prenom.nom@example.com)"
        input-title="Adresse courriel"
        placeholder="prenom.nom@example.com"
        button-text="S’abonner"
        button-title="S‘abonner à notre lettre d’information"
/>

Exemple complet

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

import DsfrFollow from '../DsfrFollow.vue'
import DsfrNewsLetter from '../DsfrNewsLetter.vue'

const title = 'Titre de la lettre d’information'
const description = 'Description de la lettre d’information'
const email = ref<string>('email.super@chouette.fr')
const labelEmail = 'Votre adresse électronique'
const inputTitle = 'Adresse électronique'
const placeholder = 'james.bond@mi6.gov.uk'
const hintText = 'En renseignant votre adresse électronique, vous acceptez de recevoir nos actualités par courriel. Vous pouvez vous désinscrire à tout moment à l’aide des liens de désinscription ou en nous contactant.'
const buttonText = 'S’abonner'
const buttonTitle = 'Titre du bouton (attribut `title`) de la balise `button`'
</script>

<template>
  <DsfrFollow>
    <!-- Important, car ce div est dans un div.fr-grid-row -->
    <div class="fr-col-12">
      <DsfrNewsLetter
        v-model:email="email"
        :title="title"
        :description="description"
        :label-email="labelEmail"
        :input-title="inputTitle"
        :placeholder="placeholder"
        :hint-text="hintText"
        :button-text="buttonText"
        :button-title="buttonTitle"
      />
    </div>
  </DsfrFollow>
</template>

⚙️Code source du composant

vue
<script lang="ts" setup>
import type { DsfrNewsLetterProps } from './DsfrFollow.types'

export type { DsfrNewsLetterProps }

withDefaults(defineProps<DsfrNewsLetterProps>(), {
  title: 'Abonnez-vous à notre lettre d’information',
  description: '',
  email: '',
  error: '',
  labelEmail: 'Votre adresse électronique (ex. : prenom.nom@example.com)',
  placeholder: 'prenom.nom@example.com',
  inputTitle: 'Adresse courriel',
  hintText: '',
  buttonText: 'S’abonner',
  buttonTitle: 'S‘abonner à notre lettre d’information',
  buttonAction: () => {},
  onSubmit: () => {},
  onlyCallout: false,
})

const emailValue = defineModel<string>('email')
</script>

<template>
  <div class="fr-follow__newsletter">
    <div>
      <h3 class="fr-h5 fr-follow__title">
        {{ title }}
      </h3>
      <p class="fr-text--sm fr-follow__desc">
        {{ description }}
      </p>
    </div>
    <div v-if="onlyCallout">
      <button
        class="fr-btn"
        :title="buttonTitle"
        @click="buttonAction ? buttonAction($event) : () => {}"
      >
        {{ buttonText }}
      </button>
    </div>
    <div v-else>
      <form @submit.prevent="onSubmit(emailValue)">
        <label
          class="fr-label"
          for="newsletter-email"
        >
          {{ labelEmail }}
        </label>
        <div class="fr-input-wrap fr-input-wrap--addon">
          <input
            id="newsletter-email"
            v-model="emailValue"
            class="fr-input"
            aria-describedby="fr-newsletter-hint-text"
            :title="inputTitle || labelEmail"
            :placeholder="placeholder || labelEmail"
            type="email"
            name="newsletter-email"
            autocomplete="email"
          >
          <button
            id="newsletter-button"
            class="fr-btn"
            :title="buttonTitle"
            type="submit"
          >
            {{ buttonText }}
          </button>
        </div>
        <div
          v-if="error"
          class="fr-messages-group"
          role="alert"
        >
          <p
            id="newsletter-email-desc-error"
            class="fr-error-text"
          >
            {{ error }}
          </p>
        </div>
        <p
          id="fr-newsletter-hint-text"
          class="fr-hint-text"
        >
          {{ hintText }}
        </p>
      </form>
    </div>
  </div>
</template>
ts
export enum DsfrSocialNetworkIcon {
  bluesky,
  dailymotion,
  facebook,
  github,
  instagram,
  linkedin,
  mastodon,
  snapchat,
  telegram,
  threads,
  tiktok,
  twitch,
  'twitter-x',
  vimeo,
  youtube,
}

export type DsfrSocialNetworkName = keyof typeof DsfrSocialNetworkIcon
export type DsfrSocialNetwork = {
  type: DsfrSocialNetworkName
  name: string
  href: string
}

export type DsfrSocialNetworksProps = {
  networks?: DsfrSocialNetwork[]
  titleTag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
}

export type DsfrNewsLetterProps = {
  title?: string
  description?: string
  email?: string
  error?: string
  labelEmail?: string
  placeholder?: string
  hintText?: string
  inputTitle?: string
  buttonText?: string
  buttonTitle?: string
  buttonAction?: ($event: MouseEvent) => void
  onSubmit?: (email: string | undefined) => void
  onlyCallout?: boolean
}

export type DsfrFollowProps = {
  newsletterData?: DsfrNewsLetterProps
  networks?: DsfrSocialNetwork[]
}