Skip to content

Dynamic Form

App.tsx
import { DynamicForm, FormField } from "kamey-components";
const App = () => {
// Definimos los campos del formulario y podemos tiparlos con FormField
const fields: FormField[] = [
{
type: 'text',
name: 'name',
label: 'Nombre',
validations: [
{
required: {
value: true,
message: 'El nombre es requerido'
}
}
],
},
{
type: 'text',
name: 'lastName',
label: 'Apellido',
validations: [
{
required: {
value: true,
message: 'El apellido es requerido'
}
}
],
},
{
type: 'email',
name: 'email',
label: 'Correo',
validations: [
{
required: {
value: true,
message: 'El correo es requerido'
}
},
{
email: {
value: true,
message: 'El correo no es válido'
}
}
],
},
{
type: 'password',
name: 'password',
label: 'Contraseña',
validations: [
{
required: {
value: true,
message: 'La contraseña es requerida'
}
}
],
}
]
return (
<div>
<DynamicForm
title='Crear Usuario'
description='Por favor, ingrese los datos del usuario'
icon={<FaUser />}
fields={fields}
submitButtonText='Crear Usuario'
/>
</div>
);
};
export default App;

Características Principales

  • ✅ Configuración declarativa de campos
  • ✅ Validaciones integradas y personalizables
  • ✅ Soporte para layouts vertical/horizontal
  • ✅ Integración con APIs (CRUD)
  • ✅ Campos responsivos en múltiples columnas
  • ✅ Modos creación/actualización

Uso Básico

// Ejemplo mínimo de implementación
<DynamicForm fields={[{ type: "text", name: "example", label: "Ejemplo" }]} />

API Reference

Propiedades del Componente

PropiedadDescripciónTipoPor defectoRequerido
modeModo de operación (‘create’ para crear nuevos registros, ‘update’ para editar)‘create’ | ‘update''create’
titleTítulo principal del formulariostring-No
descriptionTexto descriptivo debajo del títulostring | ReactElement-No
iconIcono que acompaña al títuloReactElement-No
layoutDisposicíon de los campos’vertical’ | ‘horizontal''vertical’No
colsNúmero de columnas para organización responsivanumber1No
fieldsConfiguracíon de campos del formularioFormField[] | FormField[][]-
submitButtonTextTexto personalizado para el botón de envíostring’Enviar’No
onSubmitCallback que se ejecuta al enviar el formulario(data: Record<string, unknown>) => void-No
apiConfigConfiguración para conexión con APIApiConfig-No
initialDataDatos iniciales para el modo de ediciónRecord<string, unknown>-No
customColsHabilita organización avanzada de columnasbooleanfalseNo

Tipos de Campos (FormField)

Cada campo debe contener estas propiedades básicas:

interface FormField {
type: FieldType;
name: string;
label: string;
// ... otras propiedades opcionales o que dependen del tipo de campo
}

Tipos Disponibles (FieldType)

  • text - Campo de texto simple
  • email - Campo de email con validación automática
  • password - Campo de contraseña con visibilidad ocultable
  • number - Campo numérico
  • datepicker - Selector de fecha, con soporte para formato de hora y fecha
  • rangepicker - Selector de rango de fechas
  • select - Selector de opciones, con soporte para opciones dinámicas
  • radio - Selector de opciones en radio buttons
  • checkbox - Selector de opciones en checkboxes
  • textarea - Campo de texto multilínea
  • upload - Selector de archivos, con soporte para múltiples archivos
  • slider - Selector de rango numérico
  • switch - Selector de estado binario

Ejemplo Completo de Campo

{
type: 'select',
name: 'country',
label: 'País',
options: [
{ label: 'México', value: 'MX' },
{ label: 'España', value: 'ES' }
],
validations: [
{
required: {
value: true,
message: 'Selecciona tu país'
}
}
]
}

Sistema de validación

Configura reglas de validación por campo usando el formato

{
validations: [
{
required: true // requerido con mensaje por defecto
},
{
required: { // requerido con mensaje personalizado
value: true,
message: 'Este campo es requerido'
}
},
{
email: {
value: true,
message: 'Correo no válido'
}
}
{
minLength: {
value: 5,
message: 'Mínimo 5 caracteres'
}
},
{
maxLength: {
value: 10,
message: 'Máximo 10 caracteres'
}
},
{
pattern: {
value: /^[A-Za-z]+$/,
message: 'Solo letras'
}
},
]
}

Ejemplos Avanzados

Formularios con Columnas Personalizadas

// Puedes configurar los campos a tu antojo, en una fila tener 4, en otras 2, etc.
const fields: FormField[][] = [ // Nota que este tipado es diferente, es un arreglo de arreglos
[
{ type: "text", name: "name", label: "Nombre" },
{ type: "text", name: "lastName", label: "Apellido" },
{ type: "number", name: "age", label: "Edad" },
],
[
{ type: "email", name: "email", label: "Correo" },
{ type: "password", name: "password", label: "Contraseña" },
],
]
<DynamicForm
layout='horizontal'
cols={2}
customCols // Debes habilitar esta propiedad para usar campos personalizados
fields={fields}
/>

Usando la propiedad Cols

// Esta configuración es más sencilla y automática, defines los campos como siempre
const fields: FormField[] = [
{ type: "text", name: "name", label: "Nombre" },
{ type: "text", name: "lastName", label: "Apellido" },
{ type: "number", name: "age", label: "Edad" },
{ type: "email", name: "email", label: "Correo" },
{ type: "password", name: "password", label: "Contraseña" },
]
<DynamicForm
cols={2} // Indicas cuántas columnas quieres, y el componente se encarga de distribuirlos
fields={fields}
/>

Recibir datos iniciales para edición

Imagina que tienes una vista de edición de usuario, recibes los datos del usuario ya sea de una API, por props, etc. Cuando tengas este caso, debes asegurarte que el campo name de cada FormField coincida con la clave del objeto de datos iniciales.

const initialData = {
name: "Juan",
lastName: "Perez",
email: "juan@gmail.com",
};
const fields: FormField[] = [
{ type: "text", name: "name", label: "Nombre" },
{ type: "text", name: "lastName", label: "Apellido" },
{ type: "email", name: "email", label: "Correo" },
{ type: "password", name: "password", label: "Contraseña" },
];
<DynamicForm
mode="update"
title="Editar Usuario"
description="Actualiza los datos del usuario"
icon={<FaUser />}
fields={fields}
initialData={initialData}
submitButtonText="Actualizar Usuario"
/>;

Envío de datos a una API

La forma más común de enviar datos de un formulario a una API es usando la propiedad onSubmit, que recibe un objeto con los valores de los campos.

const fields: FormField[] = [
{ type: "text", name: "name", label: "Nombre" },
{ type: "text", name: "lastName", label: "Apellido" },
{ type: "email", name: "email", label: "Correo" },
{ type: "password", name: "password", label: "Contraseña" },
];
const handleSubmit = (data: Record<string, unknown>) => {
// Aquí puedes enviar los datos a tu API
console.log(data);
};
<DynamicForm fields={fields} onSubmit={handleSubmit} />;

Buenas Prácticas

  • 🔒 Tipado de Campos: Usa la interfaz FormField para tipar los campos del formulario.
  • 📝 Validaciones Contextuales: Ajusta las validaciones según el modo (create/update) y tipo de campo.
  • 📦 Organización de Campos: Agrupa campos relacionados usando el sistema de columnas.
  • 🐛 Manejo de Errores: Implementa lógica de notificación en el callback onSubmit.

Configuración Avanzada de Campos

Selects

1. // Pasar opciones predefinidas a un campo select
{
type: 'select',
name: 'country',
label: 'País',
options: [
{ label: 'México', value: 'MX' },
{ label: 'España', value: 'ES' }
]
}
2. // Consumir opciones de una API
{
type: 'select',
name: 'city',
label: 'Ciudad',
selectConfig: {
apiConfig: { // Configuración de la API
url: 'https://api.thecompaniesapi.com/v2/locations/continents', // URL de la API
valueKey: 'code', // Clave del valor, será el valor del campo, y será el valor enviado al servidor
labelKey: 'name', // Clave de la etiqueta, será el texto mostrado en el selector
responseDataPath: 'continents', // Ruta de los datos en la respuesta de la API, muchas veces los datos vienen en .data pero puede variar
}
}
}
2.1 // También puedes consumir datos desde funciones asíncronas en lugar de una URL
{
type: 'select',
name: 'city',
label: 'Ciudad',
selectConfig: {
apiConfig: {
getterMethod: async () => getContinents(),
valueKey: 'code',
labelKey: 'name',
responseDataPath: 'countries',
}
}
}
3. // Selects dependientes: Llenar un select con base en la selección de otro
{
type: 'select',
name: 'drink',
label: 'Bebida',
selectConfig: {
apiConfig: {
url: 'https://www.thecocktaildb.com/api/json/v1/1/random.php',
valueKey: 'idDrink', // Clave del valor en la respuesta API
labelKey: 'strDrink', // Clave del texto a mostrar
responseDataPath: 'drinks' // Ruta donde están los datos en la respuesta
},
onChange: (value) => { console.log('Selected drink:', value); }
}
},
{
type: 'select',
name: 'drink_info',
label: 'Información de la bebida',
selectConfig: {
dependsOn: {
field: 'drink', // Nombre del campo padre del que depende
apiUrl: 'https://www.thecocktaildb.com/api/json/v1/1/search.php?s=:strDrink',
method: 'GET',
labelKey: 'strDrink', // Clave para el texto de las opciones
valueKey: 'idDrink', // Clave para el valor de las opciones
idPlaceholder: ':strDrink', // Marcador a reemplazar en la URLs
}
}
}

Datepickers

1. // Selector de fecha simple
{
type: 'datepicker',
name: 'birthday',
label: 'Fecha de Nacimiento'
}
2. // Formateo de fecha
{
type: 'datepicker',
name: 'birthday',
label: 'Fecha de Nacimiento',
datepickerConfig: {
format: 'DD/MM/YYYY' // Puedes configurar otras opciones como 'MM/DD/YYYY', 'YYYY-MM-DD', etc.
}
}
3. // Selector de fecha y hora
{
type: 'datepicker',
name: 'birthday',
label: 'Fecha de Nacimiento',
datepickerConfig: {
format: 'DD/MM/YYYY HH:mm' // Puedes configurar otras opciones como 'DD/MM/YYYY HH:mm:ss', etc.
showTime: true
}
}
4. // Rango de fechas
{
type: 'rangepicker',
name: 'dates',
label: 'Rango de Fechas'
}