> ## 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.

> Aprenda a usar componentes personalizados para crear campos que requieran una lógica o una interfaz de usuario específicas con JavaScript, HTML y CSS.

# Componentes de campos personalizados

<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 > Campo personalizado" 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>

Con el campo personalizado, puede ampliar la apariencia y la funcionalidad de sus formularios, y añadir una lógica potente con JavaScript, HTML y CSS.

El campo personalizado incluye métodos internos para facilitar el envío de datos al formulario, añadir validaciones de frontend y backend, y gestionar eventos comunes como focus o blur.

Puede usar el campo personalizado para crear:

* Campos con una estructura de datos personalizada.

  * **Ejemplo**: Objetos, matrices de cadenas
* Campos que usan widgets de terceros.

  * **Ejemplo**: Autocompletado de direcciones de Google
* Campos con lógica para ocultar o mostrar otros campos.
* Campos que requieren API externas para obtener un valor.

<Warning>
  Para usar campos personalizados, debe habilitar [dominios personalizados](/es/docs/customize/custom-domains). Si renderiza un formulario con un campo personalizado fuera de un dominio personalizado, se mostrará un error.
</Warning>

<div id="custom-field-settings">
  ## Configuración de campos personalizados
</div>

La configuración de los campos personalizados es la siguiente:

<div id="params">
  ### Parámetros
</div>

Agregue pares clave-valor para hacer referencia a ellos en el código fuente del campo personalizado. Los pares clave-valor pueden incluir [variables](/es/docs/customize/forms/variables) de campos del formulario.

<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">
  Los valores de los parámetros solo están disponibles después de que el formulario llame al método `init()`.
</Callout>

**Ejemplo**:

En el ejemplo siguiente, la configuración de parámetros del campo personalizado se rellena con los pares clave-valor `symbol={{fields.symbol}}` y `separator=,`

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

  function mountComponent() {
    /** El método getParams() devuelve los parámetros que configuraste en tu input */
    const config = context.custom.getParams();
    const { symbol, separator } = config;

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

  return {
    /** Se invoca una vez cuando se crea el campo */
    init() {
      mountComponent();
      return input;
    },
    ...
  };
}
```

<div id="source-code">
  ### Código fuente
</div>

Agrega tu código JavaScript al campo personalizado.

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

**Ejemplo**:

```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">
  ### Esquema JSON
</div>

De forma predeterminada, el campo personalizado acepta cualquier formato de valor. Sin embargo, puedes usar [JSON Schema](https://json-schema.org/) para validar los valores en el servidor.

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

**Ejemplo**:

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

Para adaptarte a requisitos de validación complejos, puedes usar un [flujo](/es/docs/customize/forms/flows).

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

Añade tus estilos CSS al campo personalizado.

<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">
  ## Manejadores de campos personalizados
</div>

Puedes usar estos manejadores para añadir un comportamiento personalizado al campo:

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

Se invoca una sola vez cuando se crea el campo y recibe los valores de `params` que configuras en la sección parámetro.

Devuelve un elemento HTML, una cadena o ningún valor.

**Ejemplo**:

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

init() {
  return input;
}
```

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

Se invoca cuando el usuario vuelve a visitar el mismo paso del formulario.

Esta opción es útil cuando necesita volver a renderizar la lógica de la interfaz de usuario o actualizar los valores de los parámetros que podrían haber cambiado.

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

Se invoca cuando el foco pasa al elemento HTML del campo personalizado.

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

Se invoca cuando el elemento HTML del campo personalizado pierde el foco.

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

Se invoca cuando el formulario necesita obtener el valor del campo personalizado una o varias veces. Por lo general, esto ocurre cuando el usuario envía ese paso del formulario. Si necesita realizar validaciones del lado del cliente, puede generar un error para mostrar un mensaje de error personalizado al usuario.

**Ejemplo:**

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

Se invoca cuando el campo personalizado debe bloquearse. Normalmente se ejecuta cuando el usuario envía ese paso del formulario y los datos se están procesando en nuestro backend.

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

Se invoca cuando se debe desbloquear el campo personalizado. Normalmente se ejecuta después de que el usuario envía ese paso del formulario o de que los datos dejan de procesarse en nuestro back-end debido a un error de validación.

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

Devuelve una lista de URL cuya carga el formulario garantiza que habrá finalizado antes de que se invoque el método `init()`.

**Ejemplo**:

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

<div id="context-object">
  ## Objeto de contexto
</div>

Al pasar un objeto de contexto, puedes usar estos métodos para gestionar la lógica de tu formulario y tus componentes.

<div id="custom-methods">
  ### Métodos personalizados
</div>

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

Devuelve el valor del campo personalizado actual.

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

Establece un valor para el campo personalizado actual.

**Ejemplo**:

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

Devuelve un identificador único del campo personalizado actual.

**Ejemplo**:

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

Obtiene los parámetros de la configuración actual del campo personalizado.

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  Los valores de los parámetros solo están disponibles después de que el formulario invoque el método `init()`.
</Callout>

**Ejemplo**:

```javascript lines theme={null}
function customInput(context) {
  // Acceder a los parámetros en la raíz de la función NO funciona
  // 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étodos del formulario
</div>

Cuando necesites interactuar con el formulario para obtener valores de otros campos o ir a otros pasos del formulario, puedes usar los siguientes métodos del formulario:

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

Devuelve un identificador único del formulario actual.

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

Devuelve el elemento HTML raíz del formulario actual.

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

Pasa al siguiente paso del formulario.

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

Pasa al paso anterior del formulario.

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

Devuelve un valor booleano si el formulario supera todas las validaciones del cliente.

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

Valida los valores actuales de los campos en el cliente antes de continuar. Si un campo no supera la validación, aparecerá un mensaje de error.

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

Devuelve un objeto con los valores de todos los campos ocultos.

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

Establece el valor de un campo oculto.

| Parámetro | Descripción                          |
| --------- | ------------------------------------ |
| `id`      | *String*. El ID del campo oculto.    |
| `value`   | *String*. El valor del campo oculto. |

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

Devuelve un objeto con los valores de todos los campos, incluidos los campos ocultos.

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

Devuelve una instancia del campo especificado.

* `getNode() | true` Devuelve el elemento HTML raíz del campo.
* `getValue()` Devuelve el valor del campo.
* `setRequired(boolean)` Marca o desmarca el campo como obligatorio.

| Parámetro | Descripción                           |
| --------- | ------------------------------------- |
| `id`      | \*String \*. El valor del campo `id`. |

**Ejemplo**:

```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()` solo marca o desmarca el campo como obligatorio en el cliente. Por ejemplo, si desmarca un campo como obligatorio, pero está marcado como obligatorio en la configuración del campo, el formulario devolverá un error si el campo no tiene ningún valor.
</Callout>

<div id="custom-field-examples">
  ## Ejemplos de campos personalizados
</div>

En las secciones siguientes se muestran ejemplos de campos personalizados que puedes agregar a tus formularios:

<div id="range-input-custom-field">
  ### Campo personalizado de rango
</div>

Un campo personalizado que devuelve un valor dentro de un rango predeterminado.

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

**Código fuente**:

```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">
  ### Campo personalizado de selector de color
</div>

Un campo personalizado que devuelve un valor hexadecimal de color.

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

**Código fuente**:

```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">
  ### Campo personalizado de autocompletado con valores de una API
</div>

Un campo personalizado que devuelve un valor de autocompletado mediante una API de terceros.

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

**Código fuente**:

```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">
  ### Campo personalizado con lista desplegable dinámica y valores de una API
</div>

Un campo personalizado que devuelve un valor de una lista desplegable dinámica mediante una API de terceros.

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

**Código fuente**:

```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">
  ### Campo personalizado de entrada dinámica con un botón (+) para añadir más campos
</div>

Un campo personalizado que permite a los usuarios añadir más campos.

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

**Código fuente**:

```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);
    },
  };
}
```

**Código 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);
}
```
