> ## Documentation Index
> Fetch the complete documentation index at: https://auth0.generaltranslation.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Composants de champ personnalisé

> Apprenez à utiliser les composants personnalisés pour créer des champs qui nécessitent une logique ou une interface utilisateur spécifique en utilisant JavaScript, HTML et CSS.

<Frame>
  <img src="https://mintcdn.com/generaltranslationinc/RnTJ5sT0kNq-58cb/docs/images/fr-ca/cdy7uua7fh8z/3bZUItvx7VQG1AUuTah1V0/6ba3b7e9909d189f418cdc85a5ed53b9/custom-field.png?fit=max&auto=format&n=RnTJ5sT0kNq-58cb&q=85&s=2e3d917d1deb9be483846afed0e261a3" alt="Dashboard > Actions > Forms > Custom field" data-og-width="1408" width="1408" data-og-height="850" height="850" data-path="docs/images/fr-ca/cdy7uua7fh8z/3bZUItvx7VQG1AUuTah1V0/6ba3b7e9909d189f418cdc85a5ed53b9/custom-field.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/generaltranslationinc/RnTJ5sT0kNq-58cb/docs/images/fr-ca/cdy7uua7fh8z/3bZUItvx7VQG1AUuTah1V0/6ba3b7e9909d189f418cdc85a5ed53b9/custom-field.png?w=280&fit=max&auto=format&n=RnTJ5sT0kNq-58cb&q=85&s=5faf1f4ace94b92d20353e874cc4f496 280w, https://mintcdn.com/generaltranslationinc/RnTJ5sT0kNq-58cb/docs/images/fr-ca/cdy7uua7fh8z/3bZUItvx7VQG1AUuTah1V0/6ba3b7e9909d189f418cdc85a5ed53b9/custom-field.png?w=560&fit=max&auto=format&n=RnTJ5sT0kNq-58cb&q=85&s=b22acac49ca7b7be238a727b02b49e12 560w, https://mintcdn.com/generaltranslationinc/RnTJ5sT0kNq-58cb/docs/images/fr-ca/cdy7uua7fh8z/3bZUItvx7VQG1AUuTah1V0/6ba3b7e9909d189f418cdc85a5ed53b9/custom-field.png?w=840&fit=max&auto=format&n=RnTJ5sT0kNq-58cb&q=85&s=77a13a44d87c77a6ce69048e4a4e0604 840w, https://mintcdn.com/generaltranslationinc/RnTJ5sT0kNq-58cb/docs/images/fr-ca/cdy7uua7fh8z/3bZUItvx7VQG1AUuTah1V0/6ba3b7e9909d189f418cdc85a5ed53b9/custom-field.png?w=1100&fit=max&auto=format&n=RnTJ5sT0kNq-58cb&q=85&s=7a9cbe521e5dd3de64fa07adc7273c41 1100w, https://mintcdn.com/generaltranslationinc/RnTJ5sT0kNq-58cb/docs/images/fr-ca/cdy7uua7fh8z/3bZUItvx7VQG1AUuTah1V0/6ba3b7e9909d189f418cdc85a5ed53b9/custom-field.png?w=1650&fit=max&auto=format&n=RnTJ5sT0kNq-58cb&q=85&s=d1156451d26caf08938f92f475caeec9 1650w, https://mintcdn.com/generaltranslationinc/RnTJ5sT0kNq-58cb/docs/images/fr-ca/cdy7uua7fh8z/3bZUItvx7VQG1AUuTah1V0/6ba3b7e9909d189f418cdc85a5ed53b9/custom-field.png?w=2500&fit=max&auto=format&n=RnTJ5sT0kNq-58cb&q=85&s=d0a441657885899d25a101b478271ae8 2500w" />
</Frame>

En utilisant les champs personnalisés, vous pouvez étendre l’aspect et la convivialité de vos formulaires et ajouter une logique puissante avec JavaScript, HTML et CSS.

Le champ personnalisé possède des méthodes internes qui facilitent le passage des données vers le formulaire, l’ajout de validations du côté client et dorsales et la gestion d’événements courants tels que le focus ou le brouillage (blur).

Vous pouvez personnaliser les champs pour créer :

* Des champs avec une structure de données personnalisée.

  * **Exemple** : Objets, tableau de chaînes
* Des champs qui utilisent des gadget logiciel tiers.

  * **Exemple** : Remplissage automatique Google Address
* Champs dont la logique permet de masquer ou d’afficher d’autres champs.
* Champs qui nécessitent des API externes pour obtenir une valeur.

<Warning>
  Pour utiliser les champs personnalisés, vous devez activer des [Domaines personnalisés](/docs/fr-CA/fr-ca/customize/custom-domains). L’affichage d’un formulaire avec un champ personnalisé en dehors d’un domaine personnalisé provoquera une erreur.
</Warning>

<div id="custom-field-settings">
  ## Paramètres des champs personnalisés
</div>

Les configurations de champ personnalisées sont :

<div id="params">
  ### Params
</div>

Ajoutez des paires clé-valeur à référencer dans le code source du champ personnalisé. Les paires clé-valeur peuvent inclure des [variables](/docs/fr-CA/fr-ca/customize/forms/variables) de champ de formulaire.

<Frame>
  <img src="https://mintcdn.com/generaltranslationinc/9lDbWecp3mLK18lk/docs/images/fr-ca/cdy7uua7fh8z/6VEtliKd20ZF4MJKhvB5Z0/e1b3b5df4860d013d1e3eb79d1174b35/params.png?fit=max&auto=format&n=9lDbWecp3mLK18lk&q=85&s=23250998dafa81c060f80b5274c01004" alt="" width="821" height="320" data-path="docs/images/fr-ca/cdy7uua7fh8z/6VEtliKd20ZF4MJKhvB5Z0/e1b3b5df4860d013d1e3eb79d1174b35/params.png" />
</Frame>

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  Les valeurs des paramètres ne sont disponibles qu’après que le formulaire a invoqué la méthode `init()`.
</Callout>

**Exemple** :

Dans l’exemple ci-dessous, les configurations de champ personnalisé sont remplies avec les paires clé-valeur `symbol=\{\{fields.symbol}}` et `separator=,`

```javascript lines theme={null}
function CustomComponent(context) {
  const input = document.createElement('input');
  let mask = null;

  function mountComponent() {
    /** getParams() method returns the params you've configured in your input */
    const config = context.custom.getParams();
    const { symbol, separator } = config;

    mask = IMask(input,
    {
      mask: `${symbol}num`,
      blocks: {
        num: {
          mask: Number,
          thousandsSeparator: separator,
        }
      }
    });
  }

  return {
    /** Invoked once when the field is created */
    init() {
      mountComponent();
      return input;
    },
    ...
  };
}
```

<div id="source-code">
  ### Code source
</div>

Ajoutez votre code Javascript au champ personnalisé.

<Frame>
  <img src="https://mintcdn.com/generaltranslationinc/WmK69nr0mkz5cO2-/docs/images/fr-ca/cdy7uua7fh8z/TMuY21ILSxBiBWv792cTB/97e9855145d7b52fc33ed60249e86642/source-code.png?fit=max&auto=format&n=WmK69nr0mkz5cO2-&q=85&s=ab1e04526a1d3153c57d6fb62bb4b9ee" alt="" width="958" height="405" data-path="docs/images/fr-ca/cdy7uua7fh8z/TMuY21ILSxBiBWv792cTB/97e9855145d7b52fc33ed60249e86642/source-code.png" />
</Frame>

**Exemple** :

```javascript lines theme={null}
function customInput() {
  const input = document.createElement('input');
  input.type = 'text';

  return {
    init() {
      return input;
    },

    block() {
      input.disabled = true;
    },

    unblock() {
      input.disabled = false;
    },

    getValue() {
      return input.value;
    }
  };
}
```

<div id="json-schema">
  ### Schéma JSON
</div>

Par défaut, le champ personnalisé accepte n’importe quel format de valeur. Cependant, vous pouvez utiliser [JSON Schema](https://json-schema.org/) pour valider les valeurs côté serveur.

<Frame>
  <img src="https://mintcdn.com/generaltranslationinc/2HoSdIVVjMeJSj5n/docs/images/fr-ca/cdy7uua7fh8z/5iQfwWq8Scx11s1fcSONvK/d7af907f575095d66558ee2631c73113/json-schema.png?fit=max&auto=format&n=2HoSdIVVjMeJSj5n&q=85&s=64175550b2c8aa91a00758ebf5ce1b01" alt="" width="672" height="351" data-path="docs/images/fr-ca/cdy7uua7fh8z/5iQfwWq8Scx11s1fcSONvK/d7af907f575095d66558ee2631c73113/json-schema.png" />
</Frame>

**Exemple** :

```json lines theme={null}
{
  "type": "array",
  "items": {
    "type": "string"
  },
  "minItems": 2
}
```

Pour répondre à des exigences de validation complexes, vous pouvez utiliser un [flux](/docs/fr-CA/fr-ca/customize/forms/flows).

<div id="css">
  ### CSS
</div>

Ajoutez vos styles CSS au champ personnalisé.

<Frame>
  <img src="https://mintcdn.com/generaltranslationinc/WmK69nr0mkz5cO2-/docs/images/fr-ca/cdy7uua7fh8z/lC4w1THpVDD32Ke6IsXrl/e1371beeed09d5f12b6656d397c3b692/css.png?fit=max&auto=format&n=WmK69nr0mkz5cO2-&q=85&s=72fbed9e91e39554ef8686d6a0e3edbb" alt="" width="812" height="343" data-path="docs/images/fr-ca/cdy7uua7fh8z/lC4w1THpVDD32Ke6IsXrl/e1371beeed09d5f12b6656d397c3b692/css.png" />
</Frame>

<div id="custom-field-handlers">
  ## Gestionnaires de champs personnalisés
</div>

Vous pouvez utiliser ces gestionnaires pour ajouter des comportements personnalisés aux champs :

<div id="init">
  ### init(params?)
</div>

Invoqué une fois lorsque le champ est créé et transmet les valeurs des paramètres que vous configurez dans les réglages Params.

Renvoie un élément HTML, une chaîne ou aucune valeur.

<table class="table">
  <thead>
    <tr>
      <th>Paramètre</th>
      <th>Description</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>`params`</td>

      <td>
        <p>
          <em>Objet facultatif</em>. Paramètres pris à partir des réglages des champs personnalisés.
        </p>
      </td>
    </tr>
  </tbody>
</table>

**Exemple** :

```javascript lines theme={null}
const input = document.createElement('input');
input.type = 'text';

init() {
  return input;
}
```

<div id="update">
  ### update(params?)
</div>

Invoqué lorsque l’utilisateur visite à nouveau la même étape du formulaire.

Cette option est utile lorsque vous devez restituer la logique de l’interface utilisateur ou actualiser les valeurs des paramètres qui peuvent avoir changé.

<table class="table">
  <thead>
    <tr>
      <th>Paramètre</th>
      <th>Description</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>`params`</td>

      <td>
        <p>
          <em>Objet facultatif</em>. Paramètres pris à partir des réglages des champs personnalisés.
        </p>
      </td>
    </tr>
  </tbody>
</table>

<div id="onfocus">
  ### onFocus()
</div>

Invoquée lorsque le focus entre dans l’élément HTML du champ personnalisé.

<div id="onblur">
  ### onBlur()
</div>

Invoquée lorsque le focus abandonne l’élément HTML du champ personnalisé.

<div id="getvalue">
  ### getValue()
</div>

Invoquée lorsque le formulaire doit obtenir la valeur du champ personnalisé une ou plusieurs fois. Cette fonction est généralement exécutée lorsque l’utilisateur soumet le formulaire. Si vous devez effectuer des validations côté client, vous pouvez lancer une erreur pour afficher un message d’erreur personnalisé à l’utilisateur.

**Exemple** :

```javascript lines theme={null}
function customTextInput() {
  const input = document.createElement('input');
  input.type = 'text';

  return {
    init() {
      return input;
    },

    getValue() {
      if (input.value !== 'Auth0') {
        throw new Error('The value must be Auth0')
      }

      return input.value;
    }
  };
}
```

<div id="block">
  ### block()
</div>

Invoquée lorsque le champ personnalisé doit être bloqué. Cette fonction est généralement exécutée lorsque l’utilisateur soumet l’étape du formulaire et que les données sont traitées par notre système dorsal.

<div id="unblock">
  ### unblock()
</div>

Invoquée lorsque le champ personnalisé doit être débloqué. Cette fonction est généralement exécutée après que l’utilisateur a soumis le formulaire ou que les données ont cessé d’être traitées par notre système en raison d’une erreur de validation.

<div id="getscripts">
  ### getScripts()
</div>

Renvoie une liste d’URL que les garanties de formulaire auront fini de charger avant que la méthode `init()` ne soit invoquée.

**Exemple** :

```javascript lines theme={null}
getScripts() {
  return ['https://example.com/script_a.js', 'https://example.com/script_b.js'];
}
```

<div id="context-object">
  ## Objet de contexte
</div>

Lorsque vous passez un objet de contexte, vous pouvez utiliser ces méthodes pour gérer la logique de votre formulaire et de vos composants.

<div id="custom-methods">
  ### Méthodes personnalisées
</div>

<div id="contextcustomgetvalue">
  #### context.custom.getValue()
</div>

Reçoit la valeur du champ personnalisé actuel.

<div id="contextcustomsetvalue">
  #### context.custom.setValue()
</div>

Définit une valeur pour le champ personnalisé actuel.

**Exemple** :

```javascript lines theme={null}
function customInput(context) {
  const input = document.createElement('input');
  input.type = 'text';

  input.addEventListener('change', () => {
    context.custom.setValue(input.value);
  });

  return {
    init() {
      return input;
    },
  };
}
```

<div id="contextcustomcreateuid">
  #### context.custom.createUid()
</div>

Renvoie un identifiant unique pour le champ personnalisé actuel.

**Exemple** :

```javascript lines theme={null}
function customInput(context) {
  const input = document.createElement('input');
  input.type = 'text';
  input.id = context.custom.createUid();

  return {
    init() {
      return input;
    },

    getValue() {
      return input.value;
    }
  };
}
```

<div id="contextcustomgetparams">
  #### context.custom.getParams()
</div>

Reçoit les paramètres du champ personnalisé actuel.

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  Les valeurs des paramètres ne sont disponibles qu’après que le formulaire a invoqué la méthode `init()`.
</Callout>

**Exemple** :

```javascript lines theme={null}
function customInput(context) {
  // Accessing parameters on the root of the function does NOT work
  // const { defaultValue } = context.custom.getParams();
  // console.log(defaultValue); // undefined

  function buildInput() {
    const { defaultValue } = context.custom.getParams();
    const input = document.createElement('input');
    input.type = 'text';
    input.value = defaultValue;

    return input;
  }

  return {
    init() {
      return buildInput();
    },

    getValue() {
      return input.value;
    }
  };
}
```

<div id="form-methods">
  ### Méthodes de formulaire
</div>

Lorsque vous devez interagir avec le formulaire pour recueillir des valeurs dans d’autres champs ou naviguer vers d’autres étapes du formulaire, vous pouvez utiliser les méthodes de formulaire suivantes :

<div id="contextformgetid">
  #### context.form.getId()
</div>

Renvoie un identifiant unique pour le formulaire actuel.

<div id="contextformgetroot">
  #### context.form.getRoot()
</div>

Renvoie l’élément HTML racine du formulaire actuel.

<div id="contextformgoforward">
  #### context.form.goForward()
</div>

Passe à l’étape suivante du formulaire.

<div id="contextformgoprevious">
  #### context.form.goPrevious()
</div>

Passe à l’étape précédente du formulaire.

<div id="contextformisvalid">
  #### context.form.isValid()
</div>

Renvoie une valeur booléenne si le formulaire passe toutes les validations du côté client.

<div id="contextformvalidate">
  #### context.form.validate()
</div>

Évalue les valeurs des champs existants à l’aide de la validation côté client avant de poursuivre. Si un champ ne passe pas la validation, un message d’erreur apparaît.

<div id="contextformgetallhiddenfields">
  #### context.form.getAllHiddenFields()
</div>

Renvoie un objet contenant toutes les valeurs des champs cachés.

<div id="contextformsethiddenfieldid-value">
  #### context.form.setHiddenField(id, value)
</div>

Définit une valeur pour le champ masqué.

<table class="table">
  <thead>
    <tr>
      <th>Paramètre</th>
      <th>Description</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>`id`</td>

      <td>
        <p>
          <em>Chaîne</em>. L’ID du champ masqué.
        </p>
      </td>
    </tr>

    <tr>
      <td>`value`</td>

      <td>
        <p>
          <em>Chaîne</em>. La valeur du champ masqué.
        </p>
      </td>
    </tr>
  </tbody>
</table>

<div id="contextformgetvalues">
  #### context.form.getValues()
</div>

Renvoie un objet contenant toutes les valeurs des champs et des champs cachés.

<div id="contextformgetfieldid">
  #### context.form.getField(id)
</div>

Renvoie une instance pour le champ spécifié.

* `getNode() | true` Renvoie l’élément HTML racine du champ.
* `getValue()` Renvoie la valeur du champ.
* `setRequired(boolean)` Définit ou désactive le champ selon les besoins.

<table class="table">
  <thead>
    <tr>
      <th>Paramètre</th>
      <th>Description</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>`id`</td>

      <td>
        <p>
          <em>Chaîne</em>. La valeur de l’ID du champ.
        </p>
      </td>
    </tr>
  </tbody>
</table>

**Exemple** :

```javascript lines theme={null}
const fullName = context.form.getField('full_name');
const fullNameValue = fullName.getValue();
console.log(fullNameValue); // John Doe
```

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  `setRequired()` définit ou désactive le champ comme requis côté client. Par exemple, si vous désactivez un champ qui était requis, mais qu’il a été marqué comme requis dans les paramètres de champ, le formulaire renvoie une erreur si le champ n’a pas de valeur.
</Callout>

<div id="custom-field-examples">
  ## Exemples de champs personnalisés
</div>

Les sections suivantes offrent des exemples de champs personnalisées que vous pouvez ajouter à vos formulaires :

<div id="range-input-custom-field">
  ### Champ personnalisé d’entrée de plage
</div>

Un champ personnalisé qui renvoie une valeur à partir d’une plage prédéterminée.

<Frame>
  <img src="https://mintcdn.com/generaltranslationinc/4zAuExUltEzBlp_a/docs/images/fr-ca/cdy7uua7fh8z/4afLZWM9MAXXti4F3Cuc3D/c6c6d33c650b7b9fde3de011feb82192/range-input-custom-field.png?fit=max&auto=format&n=4zAuExUltEzBlp_a&q=85&s=923bd074873de533424e829602a41df4" alt="" width="380" height="242" data-path="docs/images/fr-ca/cdy7uua7fh8z/4afLZWM9MAXXti4F3Cuc3D/c6c6d33c650b7b9fde3de011feb82192/range-input-custom-field.png" />
</Frame>

**Code source** :

```javascript lines theme={null}
function rangeInput() {
  const input = document.createElement('input');
  input.type = 'range';
  input.min= '0';
  input.max= '100';
  input.value = '0';

  return {
    init() {
      return input;
    },

    getValue() {
      return input.value;
    }
  };
}
```

<div id="color-input-custom-field">
  ### Champ personnalisé de saisie de couleur
</div>

Un champ personnalisé qui renvoie une valeur hexadécimale de couleur.

<Frame>
  <img src="https://mintcdn.com/generaltranslationinc/op3qeo8SlxWCJLLV/docs/images/fr-ca/cdy7uua7fh8z/5HAWLZJmCRlyl3dIrgzgWv/c602ccc1662d40d03898dcaa94d213dc/color-input-custom-field.png?fit=max&auto=format&n=op3qeo8SlxWCJLLV&q=85&s=b52b2b9fd3785e04345a7383aed6f87b" alt="" width="376" height="262" data-path="docs/images/fr-ca/cdy7uua7fh8z/5HAWLZJmCRlyl3dIrgzgWv/c602ccc1662d40d03898dcaa94d213dc/color-input-custom-field.png" />
</Frame>

**Code source** :

```javascript lines theme={null}
function colorInput() {
  const input = document.createElement('input');
  input.type = 'color';
  input.value = '#20c5a0';

  return {
    init() {
      return input;
    },

    getValue() {
      return input.value;
    },
  };
}
```

<div id="autocomplete-input-custom-field-using-values-from-api">
  ### Champ personnalisé de saisie de remplissage automatique utilisant les valeurs de l’API
</div>

Un champ personnalisé qui renvoie une valeur de remplissage automatique à l’aide d’une API tierce.

<Frame>
  <img src="https://mintcdn.com/generaltranslationinc/WmK69nr0mkz5cO2-/docs/images/fr-ca/cdy7uua7fh8z/l0lvyJgPLrHrLT8rpR6IF/800868d966ef5b64effbb6a3b0cabf94/autocomplete-api.png?fit=max&auto=format&n=WmK69nr0mkz5cO2-&q=85&s=31c5711513b69986bfc724dd9f67d24f" alt="" width="380" height="294" data-path="docs/images/fr-ca/cdy7uua7fh8z/l0lvyJgPLrHrLT8rpR6IF/800868d966ef5b64effbb6a3b0cabf94/autocomplete-api.png" />
</Frame>

**Code source** :

```javascript lines theme={null}
function textInputWithAutocomplete(context) {
  const input = document.createElement('input');
  input.type = 'text';

  function populateInputValue(json) {
    const { city } = json;

    input.value = city;
  }

  function fetchIpInfo() {
    const url = 'https://ipinfo.io/json';
    fetch(url)
      .then((res) => res.json())
      .then((json) => populateInputValue(json));
  }

  return {
    init() {
      fetchIpInfo();
      return input;
    },

    getValue() {
      return input.value;
    },
  };
}
```

<div id="dynamic-dropdown-custom-field-using-values-from-api">
  ### Champ personnalisé de liste déroulante dynamique utilisant des valeurs provenant d’une API
</div>

Champ personnalisé qui renvoie une valeur à partir d’une liste déroulante dynamique à l’aide d’une API tierce.

<Frame>
  <img src="https://mintcdn.com/generaltranslationinc/9lDbWecp3mLK18lk/docs/images/fr-ca/cdy7uua7fh8z/6gwOMuZaYi3dh0bkrxnKy9/33172d00e3933c74954a8ac3befaff7f/dropdowncustomfield.png?fit=max&auto=format&n=9lDbWecp3mLK18lk&q=85&s=5a6706ddab0b85afb00e12e2b2831a28" alt="" width="379" height="254" data-path="docs/images/fr-ca/cdy7uua7fh8z/6gwOMuZaYi3dh0bkrxnKy9/33172d00e3933c74954a8ac3befaff7f/dropdowncustomfield.png" />
</Frame>

**Code source** :

```javascript lines theme={null}
function dynamicDropdown() {
  const select = document.createElement('select');
  select.classList.add('af-stringField-input');

  function buildOption(data) {
    const { name: { first } } = data;
    const option = document.createElement('option');
    option.value = first;
    option.innerText = first;

    return option;
  }

  function populateNames(json) {
    const { results } = json;

    results.forEach((o) => {
      const option = buildOption(o);

      select.appendChild(option);
    });
  }

  function fetchNames() {
    const url = 'https://randomuser.me/api/?results=10&inc=name';
    fetch(url)
      .then((res) => res.json())
      .then((json) => populateNames(json));
  }

  return {
    init() {
      fetchNames();
      return select;
    },

    getValue() {
      return select.value;
    },
  };
}
```

<div id="dynamic-input-custom-field-with-a-button-to-add-more-fields">
  ### Champ personnalisé de saisie dynamique avec un bouton (+) pour ajouter d’autres champs
</div>

Un champ personnalisé qui permet aux utilisateurs d’ajouter des champs supplémentaires.

<Frame>
  <img src="https://mintcdn.com/generaltranslationinc/g_5uXNJ2fsuQgUNN/docs/images/fr-ca/cdy7uua7fh8z/7xM41qqb1zYjLAPG16wxGc/a33a3dd624222643e3f967ff35acbbac/Screenshot_2024-09-12_at_09.32.35.png?fit=max&auto=format&n=g_5uXNJ2fsuQgUNN&q=85&s=2a80e6415f83a5c6ad814a3bcd1a5fe4" alt="" width="381" height="330" data-path="docs/images/fr-ca/cdy7uua7fh8z/7xM41qqb1zYjLAPG16wxGc/a33a3dd624222643e3f967ff35acbbac/Screenshot_2024-09-12_at_09.32.35.png" />
</Frame>

**Code source** :

```javascript lines theme={null}
function DynamicInputs(context) {
  const DEFAULT_INITIAL_INPUTS = 2;
  const DEFAULT_PLACEHOLDER = 'jane.doe@example.com';
  const DEFAULT_ADD_BUTTON_TEXT = 'Add new item';
  const DEFAULT_INPUT_TYPE = 'email';
  const STATE_VALUE = {};
  const FIELD_ID = context.custom.createUid();
  let UUID_COUNTER = 0;
  let INPUTS_COUNTER = 0;

  const container = document.createElement('div');

  const inputsContainer = document.createElement('div');
  container.appendChild(inputsContainer);

  function buildAddNewItem() {
    const config = context.custom.getParams();
    const { add_button_text } = config;

    const ADD_BUTTON_TEXT = add_button_text || DEFAULT_ADD_BUTTON_TEXT;

    const addInputButton = document.createElement('button');
    addInputButton.type = 'button';
    addInputButton.classList.add('af-dynamic-input-add-button');
    addInputButton.id = `${FIELD_ID}_add-input-button`;
    addInputButton.onclick = buildInputContainer.bind(this);

    const addInputButtonIcon = document.createElement('span');
    addInputButtonIcon.classList.add('af-button', 'af-dynamic-input-add-button-icon');
    addInputButtonIcon.innerText = '+';

    const addInputButtonText = document.createElement('span');
    addInputButtonText.classList.add('af-dynamic-input-add-button-text');
    addInputButtonText.innerText = ADD_BUTTON_TEXT;

    addInputButton.appendChild(addInputButtonIcon);
    addInputButton.appendChild(addInputButtonText);
    container.appendChild(addInputButton);
  }

  function removeInput(container, input) {
    delete STATE_VALUE[input.name];
    container.remove();
  }

  function buildRemoveInputButton(container, input) {
    const button = document.createElement('button');
    button.type = 'button';
    button.classList.add('af-button', 'af-dynamic-input-remove-button');
    button.innerText = '-';
    button.onclick = removeInput.bind(this, container, input);

    INPUTS_COUNTER--;

    return button;
  }

  function buildInput() {
    const config = context.custom.getParams();
    const { placeholder, input_type } = config;

    const PLACEHOLDER = placeholder || DEFAULT_PLACEHOLDER;
    const INPUT_TYPE = input_type || DEFAULT_INPUT_TYPE;

    const input = document.createElement('input');
    input.type = INPUT_TYPE;
    input.placeholder = PLACEHOLDER;
    input.classList.add('af-stringField-input');
    input.name = `${FIELD_ID}_${UUID_COUNTER}`;
    input.id = input.name;
    input.addEventListener('change', () => {
      STATE_VALUE[input.name] = input.value;
    });

    UUID_COUNTER++;

    return input;
  }

  function buildInputContainer() {
    const container = document.createElement('div');
    container.classList.add('af-dynamic-input-container');

    const input = buildInput();
    container.appendChild(input);

    const removeButton = buildRemoveInputButton(container, input);
    container.appendChild(removeButton);

    inputsContainer.appendChild(container);

    INPUTS_COUNTER++;
  }

  function initComponent() {
    const config = context.custom.getParams();
    const { initial_inputs } = config;

    const INITIAL_INPUTS = initial_inputs || DEFAULT_INITIAL_INPUTS;
    INPUTS_COUNTER = INITIAL_INPUTS

    for (let i = 0; i < INITIAL_INPUTS; i++) {
      buildInputContainer();
    }
  }

  function blockFields(value) {
    const inputKeys = Object.keys(STATE_VALUE);

    inputKeys.forEach((o) => {
      const selector = document.getElementById(o);
      selector.disabled = value;
    });
  }

  return {
    init() {
      buildAddNewItem();
      initComponent();
      return container;
    },

    block() {
      blockFields(true);
    },

    unblock() {
      blockFields(false);
    },

    getValue() {
      return Object.values(STATE_VALUE);
    },
  };
}
```

**Code CSS :**

```csharp lines theme={null}
.af-button.af-dynamic-input-remove-button {
  width: 48px;
  color: var(--button-font-color);
  background: var(--button-background-color);
}

.af-dynamic-input-container {
  display: flex;
  margin-bottom: var(--spacing-1);
}

.af-dynamic-input-container input {
  margin-right: var(--spacing-1);
}

button.af-dynamic-input-add-button {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  margin-top: var(--spacing-1);
  display: inline-flex;
  cursor: pointer;
  align-items: center;
}

.af-button.af-dynamic-input-add-button-icon {
  background: var(--primary-color);
  width: 24px;
  padding: 0;
  height: 24px;
  border-radius: .3em;
  display: flex;
  justify-content: center;
  align-items: center;
  color: #fff;
  margin-right: var(--spacing-1);
}

.af-dynamic-input-add-button-text {
  color: var(--label-font-color);
  font-size: var(--label-font-size);
}

.af-dynamic-input-add-button:focus {
  outline: none;
}

.af-dynamic-input-add-button:hover .af-button {
  transition: filter var(--transition-normal), box-shadow var(--transition-normal);
  filter: brightness(1.1);
  box-shadow: 0 0 0 var(--outline-width) var(--outline-color), 0px 4px 8px -4px var(--shadow-color), 0px 16px 24px var(--shadow-color);
}

.af-dynamic-input-add-button:focus .af-button {
  box-shadow: 0 0 0 var(--outline-width) var(--outline-color), 0px 4px 8px -4px var(--shadow-color), 0px 16px 24px var(--shadow-color);
}
```
