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

> Découvrez comment utiliser des composants personnalisés pour créer des champs qui nécessitent une logique ou une interface utilisateur particulières à l’aide de JavaScript, HTML et CSS.

# Composants de champ personnalisé

<Frame>
  <img src="https://mintcdn.com/translations/3nS3prIggmJG9TUI/docs/images/cdy7uua7fh8z/3bZUItvx7VQG1AUuTah1V0/6ba3b7e9909d189f418cdc85a5ed53b9/custom-field.png?fit=max&auto=format&n=3nS3prIggmJG9TUI&q=85&s=95b1437db66cd9cde17d02d58affdce8" alt="Dashboard > Actions > Forms > Champ personnalisé" data-og-width="1408" width="1408" data-og-height="850" height="850" data-path="docs/images/cdy7uua7fh8z/3bZUItvx7VQG1AUuTah1V0/6ba3b7e9909d189f418cdc85a5ed53b9/custom-field.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/translations/3nS3prIggmJG9TUI/docs/images/cdy7uua7fh8z/3bZUItvx7VQG1AUuTah1V0/6ba3b7e9909d189f418cdc85a5ed53b9/custom-field.png?w=280&fit=max&auto=format&n=3nS3prIggmJG9TUI&q=85&s=a48fc426395506412dd8f92f85cdef5c 280w, https://mintcdn.com/translations/3nS3prIggmJG9TUI/docs/images/cdy7uua7fh8z/3bZUItvx7VQG1AUuTah1V0/6ba3b7e9909d189f418cdc85a5ed53b9/custom-field.png?w=560&fit=max&auto=format&n=3nS3prIggmJG9TUI&q=85&s=3975b492b7a9db0a984c74c03ed767e6 560w, https://mintcdn.com/translations/3nS3prIggmJG9TUI/docs/images/cdy7uua7fh8z/3bZUItvx7VQG1AUuTah1V0/6ba3b7e9909d189f418cdc85a5ed53b9/custom-field.png?w=840&fit=max&auto=format&n=3nS3prIggmJG9TUI&q=85&s=9e0c23270d3e16dda762e669fc2a740f 840w, https://mintcdn.com/translations/3nS3prIggmJG9TUI/docs/images/cdy7uua7fh8z/3bZUItvx7VQG1AUuTah1V0/6ba3b7e9909d189f418cdc85a5ed53b9/custom-field.png?w=1100&fit=max&auto=format&n=3nS3prIggmJG9TUI&q=85&s=8a4fd3d926b9030f84c4779efd38cd2c 1100w, https://mintcdn.com/translations/3nS3prIggmJG9TUI/docs/images/cdy7uua7fh8z/3bZUItvx7VQG1AUuTah1V0/6ba3b7e9909d189f418cdc85a5ed53b9/custom-field.png?w=1650&fit=max&auto=format&n=3nS3prIggmJG9TUI&q=85&s=4938b324f243a4341c73fb741175c62e 1650w, https://mintcdn.com/translations/3nS3prIggmJG9TUI/docs/images/cdy7uua7fh8z/3bZUItvx7VQG1AUuTah1V0/6ba3b7e9909d189f418cdc85a5ed53b9/custom-field.png?w=2500&fit=max&auto=format&n=3nS3prIggmJG9TUI&q=85&s=582b9437250ab7132d0d73adf82bc951 2500w" />
</Frame>

Le champ personnalisé vous permet d’enrichir l’apparence de vos formulaires et d’ajouter une logique puissante avec JavaScript, HTML et CSS.

Le champ personnalisé comprend des méthodes internes qui facilitent la transmission des données au formulaire, l’ajout de validations côté client et côté serveur, ainsi que la gestion d’événements courants comme focus ou blur.

Vous pouvez utiliser le champ personnalisé pour créer :

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

  * **Exemple** : objets, tableau de chaînes de caractères
* Des champs qui utilisent des widgets tiers.

  * **Exemple** : autocomplétion d’adresse Google
* Des champs avec une logique permettant de masquer ou d’afficher d’autres champs.
* Des champs qui nécessitent des API externes pour obtenir une valeur.

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

<div id="custom-field-settings">
  ## Paramètres du champ personnalisé
</div>

Les paramètres du champ personnalisé sont les suivants :

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

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

<Frame>
  <img src="https://mintcdn.com/translations/6GE5Z24GDCZehiJ9/docs/images/cdy7uua7fh8z/6VEtliKd20ZF4MJKhvB5Z0/e1b3b5df4860d013d1e3eb79d1174b35/params.png?fit=max&auto=format&n=6GE5Z24GDCZehiJ9&q=85&s=1b013cace644247d8f22e9c3175e5b47" alt="" width="821" height="320" data-path="docs/images/cdy7uua7fh8z/6VEtliKd20ZF4MJKhvB5Z0/e1b3b5df4860d013d1e3eb79d1174b35/params.png" />
</Frame>

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

**Exemple** :

Dans l’exemple ci-dessous, les paramètres du champ personnalisé sont définis avec les paires clé-valeur `symbol={{fields.symbol}}` et `separator=,`

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

  function mountComponent() {
    /** La méthode getParams() retourne les params que vous avez configurés dans votre champ */
    const config = context.custom.getParams();
    const { symbol, separator } = config;

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

  return {
    /** Invoqué une seule fois à la création du champ */
    init() {
      mountComponent();
      return input;
    },
    ...
  };
}
```

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

Ajoutez votre code Javascript dans le champ personnalisé.

<Frame>
  <img src="https://mintcdn.com/translations/mMSz-RNYLuOm2GmQ/docs/images/cdy7uua7fh8z/TMuY21ILSxBiBWv792cTB/97e9855145d7b52fc33ed60249e86642/source-code.png?fit=max&auto=format&n=mMSz-RNYLuOm2GmQ&q=85&s=88f456ff9461b3c4cba9cba9a07d1b5e" alt="" width="958" height="405" data-path="docs/images/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">
  ### JSON Schema
</div>

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

<Frame>
  <img src="https://mintcdn.com/translations/MV7tE-x71x8RWRES/docs/images/cdy7uua7fh8z/5iQfwWq8Scx11s1fcSONvK/d7af907f575095d66558ee2631c73113/json-schema.png?fit=max&auto=format&n=MV7tE-x71x8RWRES&q=85&s=e05f71d747f278a2308e6bb77c3d1f6d" alt="" width="672" height="351" data-path="docs/images/cdy7uua7fh8z/5iQfwWq8Scx11s1fcSONvK/d7af907f575095d66558ee2631c73113/json-schema.png" />
</Frame>

**Exemple**:

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

Pour gérer des exigences de validation complexes, vous pouvez utiliser un [flow](/docs/fr-ca/customize/forms/flows).

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

Ajoutez vos styles CSS dans le champ personnalisé.

<Frame>
  <img src="https://mintcdn.com/translations/xwVvTWJUElMm5YAK/docs/images/cdy7uua7fh8z/lC4w1THpVDD32Ke6IsXrl/e1371beeed09d5f12b6656d397c3b692/css.png?fit=max&auto=format&n=xwVvTWJUElMm5YAK&q=85&s=69e9937c82fe8d0fa2c2add0d1ff64b8" alt="" width="812" height="343" data-path="docs/images/cdy7uua7fh8z/lC4w1THpVDD32Ke6IsXrl/e1371beeed09d5f12b6656d397c3b692/css.png" />
</Frame>

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

Vous pouvez utiliser ces gestionnaires pour personnaliser le comportement du champ :

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

Appelée une seule fois lors de la création du champ et reçoit les valeurs de `params` que vous configurez dans les paramètres de Params.

Retourne un élément HTML, une chaîne de caractères ou aucune valeur.

**Exemple**:

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

init() {
  return input;
}
```

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

Appelée lorsque l’utilisateur revient à la même étape du formulaire.

Cette option est utile lorsque vous devez relancer la logique de rendu de l’UI ou actualiser les valeurs des params qui ont pu changer.

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

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

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

Appelée lorsque le focus quitte l’élément HTML du champ personnalisé.

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

Invoquée lorsque le formulaire doit récupérer la valeur du champ personnalisé une ou plusieurs fois. Cette fonction est généralement appelée lorsque l’utilisateur soumet l’étape du formulaire. Si vous devez effectuer des validations côté client, vous pouvez lever 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>

Appelée lorsque le champ personnalisé doit être bloqué. Elle est généralement exécutée lorsque l’utilisateur soumet l’étape du formulaire et que les données sont en cours de traitement sur notre backend.

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

Appelée lorsque le champ personnalisé doit être débloqué. Cette opération est généralement exécutée après que l’utilisateur a soumis l’étape du formulaire ou que le traitement des données par notre back-end a cessé en raison d’une erreur de validation.

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

Retourne une liste d’URL dont le formulaire garantit le chargement complet avant l’appel de la méthode `init()`.

**Exemple** :

```js 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 transmettez 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>

Retourne la valeur du champ personnalisé actuel.

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

Attribue une valeur au 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 l’identifiant unique du 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>

Récupère les paramètres du champ personnalisé actuel.

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

**Exemple** :

```javascript lines theme={null}
function customInput(context) {
  // L'accès aux paramètres à la racine de la fonction ne fonctionne PAS
  // 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 du formulaire
</div>

Lorsque vous devez interagir avec le formulaire pour obtenir les valeurs d’autres champs ou passer à d’autres étapes du formulaire, vous pouvez utiliser les méthodes de formulaire suivantes :

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

Renvoie l’identifiant unique du formulaire actuel.

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

Retourne 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>

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

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

Retourne un booléen indiquant si le formulaire passe toutes les validations côté client.

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

Valide les valeurs de champ existantes au moyen de la validation côté client avant de poursuivre. Si un champ ne satisfait pas à la validation, un message d'erreur s'affiche.

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

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

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

Définit la valeur d’un champ masqué.

| Paramètre | Description                          |
| --------- | ------------------------------------ |
| `id`      | *String*. L’ID du champ masqué.      |
| `value`   | *String*. La valeur du champ masqué. |

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

Retourne un objet contenant toutes les valeurs des champs, y compris les champs masqués.

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

Retourne une instance du champ spécifié.

* `getNode() | true` Retourne l’élément HTML racine du champ.
* `getValue()` Retourne la valeur du champ.
* `setRequired(boolean)` Définit ou supprime le caractère obligatoire du champ.

| Paramètre | Description                         |
| --------- | ----------------------------------- |
| `id`      | \*String \*. La valeur du champ ID. |

**Exemple** :

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

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  `setRequired()` sert uniquement à définir ou à retirer le caractère obligatoire du champ côté client. Par exemple, si vous retirez le caractère obligatoire d’un champ, mais qu’il est marqué comme obligatoire dans les paramètres du champ, le formulaire renverra une erreur si ce champ n’a aucune valeur.
</Callout>

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

Les sections suivantes présentent des exemples de champs personnalisés que vous pouvez ajouter à vos formulaires :

<div id="range-input-custom-field">
  ### Champ personnalisé de type plage
</div>

Un champ personnalisé qui retourne une valeur dans une plage prédéfinie.

<Frame>
  <img src="https://mintcdn.com/translations/pvjQqAy3EB2TK6NP/docs/images/cdy7uua7fh8z/4afLZWM9MAXXti4F3Cuc3D/c6c6d33c650b7b9fde3de011feb82192/range-input-custom-field.png?fit=max&auto=format&n=pvjQqAy3EB2TK6NP&q=85&s=975aaade4577fdfa85070141250517a8" alt="" width="380" height="242" data-path="docs/images/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 correspondant à une couleur.

<Frame>
  <img src="https://mintcdn.com/translations/MV7tE-x71x8RWRES/docs/images/cdy7uua7fh8z/5HAWLZJmCRlyl3dIrgzgWv/c602ccc1662d40d03898dcaa94d213dc/color-input-custom-field.png?fit=max&auto=format&n=MV7tE-x71x8RWRES&q=85&s=933a4b444ad650f36e106deadd1bb867" alt="" width="376" height="262" data-path="docs/images/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 semi-automatique utilisant les valeurs d’une API
</div>

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

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

**Code source**:

```javascript lines expandable 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 avec des valeurs provenant d’une API
</div>

Un champ personnalisé qui renvoie une valeur à partir d’une liste déroulante dynamique alimentée par une API tierce partie.

<Frame>
  <img src="https://mintcdn.com/translations/6GE5Z24GDCZehiJ9/docs/images/cdy7uua7fh8z/6gwOMuZaYi3dh0bkrxnKy9/33172d00e3933c74954a8ac3befaff7f/dropdowncustomfield.png?fit=max&auto=format&n=6GE5Z24GDCZehiJ9&q=85&s=85158ae8120598750cdf07f5bbc5041a" alt="" width="379" height="254" data-path="docs/images/cdy7uua7fh8z/6gwOMuZaYi3dh0bkrxnKy9/33172d00e3933c74954a8ac3befaff7f/dropdowncustomfield.png" />
</Frame>

**Code source** :

```javascript lines expandable 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é à saisie dynamique avec un bouton (+) pour ajouter d’autres champs
</div>

Un champ personnalisé qui permet aux utilisateurs d’ajouter d’autres champs.

<Frame>
  <img src="https://mintcdn.com/translations/c0RQ9V0YAcT0-8l5/docs/images/cdy7uua7fh8z/7xM41qqb1zYjLAPG16wxGc/a33a3dd624222643e3f967ff35acbbac/Screenshot_2024-09-12_at_09.32.35.png?fit=max&auto=format&n=c0RQ9V0YAcT0-8l5&q=85&s=60099231db9f4e90097cd87a61e055d6" alt="" width="381" height="330" data-path="docs/images/cdy7uua7fh8z/7xM41qqb1zYjLAPG16wxGc/a33a3dd624222643e3f967ff35acbbac/Screenshot_2024-09-12_at_09.32.35.png" />
</Frame>

**Code source**:

```javascript lines expandable 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 :**

```css lines expandable 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);
}
```
