Librería de Formularios para Angular | ng-hub-ui-forms
Campos de formulario accesibles para Angular (input, textarea, slider, select, datepicker) con visualización automática de errores de control/grupo/form, formularios reactivos y variables CSS.
Referencia API
Aquí tienes el contrato completo de forms: todo lo que puedes enlazar, escuchar, proyectar y personalizar, reunido en un solo sitio. Enlaza lo que necesites y dale el estilo que quieras — es standalone y reactivo con signals.
Inputs
Ajusta forms a tu gusto con 87 inputs. Se enlazan como cualquier @Input de Angular.
| Nombre | Tipo | Por defecto | Descripción |
|---|---|---|---|
formControlName / [formControl] | string | FormControl | — | Vincula cualquier campo a un control reactivo. Los errores se muestran automáticamente cuando el control ha sido tocado y es inválido. |
label | string | '' | Texto de la etiqueta del campo. |
labelType (hub-input, hub-select, hub-datepicker) | 'stacked' | 'floating' | 'horizontal' | 'stacked' | Posición de la etiqueta. `floating` coloca la etiqueta dentro del control, donde hace las veces de placeholder hasta que el campo recibe el foco o tiene valor. |
labelType (hub-textarea, hub-otp-input, hub-slider, hub-segmented, hub-timepicker) | 'stacked' | 'horizontal' | 'stacked' | Posición de la etiqueta. Estos campos no tienen variante flotante: si se les pasa `floating`, renderizan una etiqueta apilada. |
placeholder (hub-input, hub-select, hub-textarea, hub-datepicker) | string | '' / NgSelectConfig.placeholder (hub-select) | Texto del placeholder. |
formText | string | — | Texto de ayuda que se muestra debajo del control. |
type (hub-input) — file is deprecated | 'text' | 'number' | 'password' | 'email' | 'tel' | 'url' | 'color' | 'checkbox' | 'switch' | 'counter' | 'file' | 'text' | El formato de hub-input. |
passwordRevealed (hub-input) | boolean | false | Estado bidireccional de visibilidad de un campo de contraseña. Al pulsar el botón del ojo se actualiza; al establecerlo se revela o se oculta el valor. |
passwordToggle (hub-input) | boolean | true | Indica si se renderiza el botón integrado para mostrar/ocultar la contraseña. |
hideOnBlur (hub-input) | boolean | true | Indica si una contraseña revelada se vuelve a ocultar automáticamente al perder el foco el campo. |
capsLockWarning (hub-input) | boolean | true | Indica si se muestra un aviso bajo el campo mientras Bloq Mayús está activo. |
passwordStrength (hub-input) | boolean | false | Renderiza un medidor de fortaleza opcional de 4 segmentos bajo el campo. La puntuación se puede sobrescribir mediante provideHubForms. |
autocomplete (hub-input) | string | '' | Atributo autocomplete nativo, p. ej. current-password o new-password para gestores de contraseñas. |
clearable (hub-input) | boolean | false | Si es true, muestra un botón ✕ interno cuando el campo tiene valor; limpia el control y emite un término de búsqueda vacío. |
debounceTime (hub-input) | number | 0 | Debounce en milisegundos antes de emitir el evento search (0 = cada pulsación). |
mask (hub-input) | string | — | Máscara de patrón para formatos de texto. Tokens: 0 = dígito, A = letra, * = alfanumérico; el resto de caracteres son separadores literales. P. ej. "0000 0000 0000 0000". |
unmaskValue (hub-input) | boolean | false | Con una máscara definida, almacena en el formulario los caracteres escritos en bruto (sin separadores) en lugar del texto formateado. |
range (hub-slider) | boolean | false | Slider de rango de doble control; el valor pasa a ser una tupla [lower, upper]. |
options (hub-segmented) | HubSegmentedOption[] | [] | Las opciones seleccionables de hub-segmented, en orden de renderizado — cada una { value, label, disabled? }. |
size (hub-segmented) | 'sm' | 'md' | 'lg' | 'md' | Densidad visual del control segmentado: 'sm', 'md' (por defecto) o 'lg'. |
disabled (all fields) | boolean (two-way, model) | false | Deshabilita el campo. Todos los campos lo heredan de la base común, y es bidireccional: un campo deshabilitado a través de su control reactivo informa del cambio de vuelta. En `hub-segmented`, las opciones individuales también pueden excluirse mediante `option.disabled`. |
multiple (hub-segmented) | boolean | false | Permite seleccionar más de una opción; el valor pasa a ser un array y las opciones alternan (aria-pressed). |
vertical (hub-segmented) | boolean | false | Apila los segmentos verticalmente en vez de en una fila horizontal. |
vertical (hub-select) — deprecated | boolean | false | Obsoleto, y ligado a los formatos obsoletos distintos de dropdown: dispone las opciones de buttons/checkbox/radio en vertical. Usa `<hub-segmented [vertical]="true">`. |
color (hub-segmented) | 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'neutral' | string | '' | Acento semántico del segmento seleccionado (primary, success, …) o cualquier color; se desliza en modo single. |
value (hub-segmented) | unknown | unknown[] | undefined | Valor seleccionado con enlace bidireccional (model()): el valor de la opción elegida en modo single, un array de valores seleccionados en modo múltiple. Emite valueChange; normalmente se gobierna mediante formControlName. |
format (hub-select) — deprecated for buttons/checkbox/radio | 'dropdown' | 'buttons' | 'checkbox' | 'radio' | 'dropdown' | Cómo renderiza el select el mismo valor. |
prepend / append (hub-input, hub-select, hub-textarea, hub-datepicker, hub-timepicker) | string | string[] | '' | Complementos estáticos de grupo en cualquier campo que se represente como una caja: una cadena es un complemento, un array es una serie de ellos, y las entradas vacías se descartan en lugar de dibujarse como una caja vacía. El complemento comparte el borde del campo y no es enfocable; para un control interactivo adosado al borde, usa las plantillas [hubPrepend] / [hubAppend]. Ambos pueden estar presentes, y el contenido proyectado siempre es el elemento más exterior de su lado. |
items / bindLabel / bindValue / multiple (hub-select) | any[] / string / string / boolean | — | Opciones, los nombres de propiedad label/value para elementos de tipo objeto, y selección múltiple. |
groupBy (hub-select) | string | undefined | undefined | Nombre de propiedad (ruta con puntos) usado para agrupar los elementos del dropdown bajo cabeceras de grupos de opciones. |
searchable / clearable (hub-select) | boolean | true | Si las opciones se pueden filtrar escribiendo (searchable) y si la selección se puede limpiar con el botón de limpieza integrado (clearable). Ambos son true por defecto. |
closeOnSelect (hub-select) | boolean | true | Si el dropdown se cierra tras seleccionar un elemento. Ponlo a false para mantenerlo abierto mientras eliges varios valores en modo múltiple. |
fixedPlaceholder (hub-select) | boolean | false | Mantiene el placeholder visible incluso cuando hay un valor seleccionado. Por defecto es false (el placeholder se oculta al seleccionar), invirtiendo el poco convencional valor por defecto de ng-select v23. |
loading / notFoundText (hub-select) | boolean / string | false / NgSelectConfig.notFoundText | loading renderiza el estado de carga del dropdown mientras se obtienen los elementos asíncronos; notFoundText es el mensaje que se muestra cuando ningún elemento coincide con el término de búsqueda. |
readonly (hub-input, hub-select, hub-textarea, hub-datepicker, hub-otp-input, hub-timepicker) | boolean | false | Cuando es true, el campo muestra su valor pero rechaza cualquier interacción, sin el estilo de deshabilitado ni el cambio de estado del formulario. |
appendTo (hub-select) | string | undefined | 'body' | Selector CSS del elemento al que se adjunta el panel del dropdown. Por defecto es 'body', de modo que el panel escapa de ancestros con overflow/transform (tarjetas, contenedores con scroll, modales); pasa undefined para renderizarlo inline. |
addTag (hub-select) | boolean | ((term: string) => any | Promise<any>) | false | Crea elementos a partir del término de búsqueda (formato dropdown): true añade el término tal cual; una función transforma el término en un elemento nuevo, síncrona o con Promise. |
addTagText (hub-select) | string | NgSelectConfig.addTagText | Etiqueta de la fila «añadir elemento» que se muestra al escribir cuando addTag está activado. |
minTermLength (hub-select) | number | 0 | Longitud mínima del término de búsqueda antes de que arranque el filtrado (o el Subject de typeahead). |
typeahead (hub-select) | Subject<string> | undefined | undefined | Subject que recibe los cambios del término de búsqueda para carga asíncrona/en servidor; cuando se proporciona, el filtrado en cliente se desactiva — devuelve los resultados a través de items. |
compareWith (hub-select) | ((a: any, b: any) => boolean) | undefined | undefined | Igualdad personalizada entre un elemento y el valor vinculado (p. ej. objetos comparados por id); si se omite, se aplica la comparación integrada del proveedor. |
searchFn (hub-select) | ((term: string, item: any) => boolean) | undefined | undefined | Sustituye la coincidencia integrada que usa `searchable`. Recibe el término escrito y un elemento, y devuelve si el elemento coincide — de modo que una búsqueda puede mirar campos que la etiqueta no muestra. |
mode (hub-datepicker) | 'single' | 'range' | 'day-time-range' | 'single' | Fecha única, rango libre de fechas, o un solo día con hora de inicio y fin dentro de él. |
granularity (hub-datepicker) | 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second' | 'day' | Precisión que lleva cada punto seleccionado, y panel que lo selecciona: year y month dibujan una rejilla de 12 celdas, day el calendario, y hour, minute y second le añaden una franja de hora. Es ortogonal a mode: mode dice cuántos puntos se eligen y granularity con qué precisión cada uno. Por defecto es day, que emite el mismo string YYYY-MM-DD de siempre; a partir de hour el valor es una marca de tiempo ISO 8601 completa con la hora local del lector y el desfase de esa fecha. |
valueFormat / parse (hub-datepicker) | 'iso' | 'date' | 'timestamp' | ((date) => unknown) / ((raw) => Date | null) | null | 'iso' / null | Los ejes del valor. valueFormat define qué guarda el control enlazado: 'iso' (por defecto), 'date' para un Date nativo, 'timestamp' para milisegundos de época, o una función para cualquier otra cosa. parse define cómo se lee un valor entrante y sustituye a la detección automática de strings ISO de cualquier anchura, instancias de Date y milisegundos de época; se aplica también a min y max. |
minuteStep / secondStep / hourFormat (hub-datepicker) | number / number / '12' | '24' | undefined | 5 / 1 / undefined | Controles de hora: minuteStep y secondStep son los incrementos de los spinbuttons, y hourFormat fuerza un reloj de 12 o de 24 horas; si no se indica, se deriva del locale, y se aplica tanto a la visualización del campo como al panel, de modo que los dos nunca puedan contradecirse. Los tres recurren a la configuración global de provideHubForms. |
min / max / disabledDates (hub-datepicker) | string | Date | number | null / ((date: Date) => boolean) | null | null | Límites seleccionables y un predicado de deshabilitado por fecha. Los límites respetan la hora, no sólo el día: un día sólo se deshabilita cuando ningún instante suyo está permitido, así que min = 2026-09-01T14:00 deja el 1 de septiembre pulsable y son los controles de hora los que rechazan las horas anteriores. Acepta un string ISO, un Date o milisegundos de época. |
locale / firstDayOfWeek / weekdayFormat (hub-datepicker) | string / number / 'short' | 'narrow' | 'long' | LOCALE_ID / undefined / undefined | i18n del calendario: locale es la etiqueta BCP-47 para el valor mostrado y los nombres de meses/días de la semana (por defecto usa el LOCALE_ID de la app, con en-US como último recurso); firstDayOfWeek establece el primer día de la semana (0 = domingo, 1 = lunes…); weekdayFormat elige el ancho de la cabecera de los días de la semana. Los dos últimos caen a la configuración global de provideHubForms. |
displayFormat / timeDisplayFormat / rangeSeparator / labels (hub-datepicker) | Intl.DateTimeFormatOptions | string | ((date) => string) / Intl.DateTimeFormatOptions / string / Partial<HubDatepickerLabels> | undefined / undefined / undefined / {} | Formato de visualización: displayFormat renderiza el valor seleccionado y acepta Intl.DateTimeFormatOptions, un patrón de fecha de Angular como 'dd/MM/yyyy HH:mm', o una función; timeDisplayFormat se compone sobre él en cuanto la granularidad lleva hora, de modo que la parte de fecha conserva lo que dijera displayFormat; rangeSeparator es el texto entre las dos fechas de un rango; y labels sobrescribe las etiquetas de la interfaz por instancia (mezcladas sobre la configuración global). |
clearable / showToday / closeOnSelect (hub-datepicker) | boolean | true / true / true | Flags de comportamiento: clearable muestra el atajo de limpiar, showToday muestra el atajo de «hoy» y closeOnSelect cierra el calendario tras elegir una fecha (solo en modo single). Por defecto: true / true / true. |
multiple (hub-file-input) | boolean | false | Si se puede contener más de un fichero. Cambia el valor del control de File a File[]. |
accept (hub-file-input) | string | '*' | Tipos aceptados, p. ej. image/*,.pdf. Se aplica también al soltar y al pegar, no solo en el diálogo del sistema. |
maxSize / minSize / maxTotalSize (hub-file-input) | number | null | null | Tamaño máximo y mínimo por fichero, y tamaño máximo combinado, en bytes. |
maxFiles (hub-file-input) | number | null | null | Número máximo de ficheros. Solo tiene sentido junto con multiple. |
dragDrop / paste (hub-file-input) | boolean | true | Si se pueden soltar ficheros sobre el campo y si se pueden pegar en él. |
preview (hub-file-input) | 'none' | 'list' | 'grid' | 'list' | Cómo se muestran los ficheros: sin previsualización, como lista o como rejilla de miniaturas. |
allowDuplicates (hub-file-input) | boolean | false | Si se puede seleccionar dos veces el mismo fichero (clave: nombre, tamaño y fecha de modificación). |
capture (hub-file-input) | 'user' | 'environment' | null | null | Abre la cámara del dispositivo en lugar del explorador de ficheros, en las plataformas que lo admiten. |
autoUpload (hub-file-input) | boolean | true | Si un fichero recién aceptado empieza a subirse de inmediato. Se ignora si no hay uploader registrado. |
buttonLabel / hint (hub-file-input) | string | null | null | Sustituye el texto del botón de examinar y la pista de restricciones autogenerada. |
dropText / dropSubtext (hub-file-input) | string | null | null | Sustituye por instancia las dos líneas de invitación de la zona de soltar. Ambas caen a los labels globales. |
classlist (every field except hub-segmented and hub-legend) | string | '' | Clases CSS adicionales aplicadas al elemento anfitrión. |
showValid (all fields) | boolean | HubFormsConfig.showValid | Si un campo válido muestra su estado de validez. Desactivado por defecto porque un formulario que pinta de verde todos los campos sin tocar no dice nada; el estado inválido se muestra siempre. |
validFeedback (all fields) | string | null | null | Mensaje que se renderiza bajo el campo una vez que es válido, cuando `showValid` está activado. |
invalidFeedbackTemplateFn (all fields) | ((key: string, value: any) => string) | null | null | Sobrescribe el mensaje de una clave de error concreta solo en este campo. Recibe la clave de error y su valor, y devuelve el texto — el valor por defecto para toda la aplicación vive en `provideHubForms`. |
min / max (hub-input) | number | undefined (two-way, model) | undefined | Límites numéricos para los formatos number y counter. Son bidireccionales: un counter que acota su propio valor informa del límite de vuelta. |
mode (hub-otp-input) | 'numeric' | 'alphanumeric' | 'alpha' | 'numeric' | Qué caracteres acepta cada celda y qué teclado ofrece un móvil: solo dígitos, o letras y dígitos. |
min / max (hub-timepicker) | string (HH:MM) | '' | Hora mínima y máxima que acepta el campo, como `HH:MM`. Vacío significa sin límite. |
step (hub-timepicker) | number (seconds) | 0 | Granularidad del stepper nativo, en segundos. `0` deja el valor por defecto del navegador, de un minuto. |
group / groupName (form[hubForm], hub-fieldset) | AbstractControl | null / string | undefined | null / undefined | El grupo cuyos errores expone el contenedor. Pasa a `group` un `AbstractControl` directamente, o a `groupName` el nombre de un hijo del formulario que lo rodea — ninguno de los dos hace falta cuando el contenedor ya envuelve el grupo del que informa. |
errorTrigger (form[hubForm], hub-fieldset) | 'touched' | 'submit' | 'always' | 'touched' | Cuándo se hacen visibles los errores a nivel de grupo: en cuanto el grupo ha sido tocado, solo tras un intento de envío, o de inmediato. |
formTextType (all fields) | 'bottom' | — | Ubicación del texto de ayuda. Solo se admite `bottom`. |
rows (hub-textarea) | number | — | Número de filas de texto visibles. |
cols (hub-textarea) | number | — | Número de columnas visibles. Cuando se define, el textarea deja de ocupar todo el ancho. |
maxlength (hub-textarea) | number | — | Número máximo de caracteres. Gobierna tanto el límite nativo como el contador. |
counter (hub-textarea) | boolean | — | Si se muestra un contador de caracteres bajo el control. |
autoresize (hub-textarea) | boolean | — | Si el textarea crece para ajustarse a su contenido. |
length (hub-otp-input) | number | — | Número de celdas o caracteres del código. |
secret (hub-otp-input) | boolean | — | Enmascara los caracteres como una contraseña. |
separator (hub-otp-input) | string | — | El carácter separador que se muestra entre grupos. |
separatorEvery (hub-otp-input) | number | — | Inserta un separador visual cada N celdas (0 = ninguno). |
showValue (hub-slider) | boolean | — | Si se muestran las burbujas de valor sobre los manejadores. |
step (hub-input, hub-slider) | number | — | Valor del incremento (entradas numéricas o de contador). |
legend (hub-fieldset) | string | — | Texto de la leyenda. Se ignora cuando se proyecta una plantilla `hubLegend`. |
required (all fields) | boolean | null (two-way, model) | null | Si el campo es obligatorio. Con un enlace reactivo se deriva de los propios validadores del control, así que asignarlo directamente en la plantilla solo se respeta en los campos template-driven; gobierna el asterisco y el atributo `required`. |
required (hub-legend) | boolean | — | Si se representa el indicador de campo obligatorio. |
invalid (hub-legend) | boolean | — | Si se aplica el estilo de estado inválido. |
Outputs
Reacciona a lo que hace forms: 13 eventos a los que enganchar tu lógica.
| Nombre | Tipo | Descripción |
|---|---|---|
valueChange | EventEmitter<value> | Se emite cada vez que cambia el valor del campo. |
search (hub-input) | EventEmitter<string> | Término de typeahead con debounce emitido mientras el usuario escribe (inputs de texto). |
rejected (hub-file-input) | EventEmitter<HubFileRejection[]> | Los ficheros rechazados por las restricciones declaradas, cada uno con el motivo del rechazo. |
fileRemoved (hub-file-input) | EventEmitter<File> | El fichero eliminado de la selección. |
uploadStateChange (hub-file-input) | EventEmitter<readonly HubFileItem[]> | La lista completa de elementos cada vez que una subida cambia de estado o de progreso. |
submit (form[hubForm]) — the native event | SubmitEvent (native, not a custom output) | No es un output propio: `hubForm` escucha el evento `submit` del propio formulario, evita la navegación por defecto, marca el árbol como tocado y activa el estado submitted. Enlaza `(submit)` en el formulario para tu propio manejador. |
disabledChange / requiredChange (all fields) · labelTypeChange / placeholderChange / minChange / maxChange / passwordRevealedChange (hub-input) · valueChange (hub-segmented) | EventEmitter<T> (the paired half of each two-way model) | Cada input bidireccional `model()` publica un output `Change` equivalente, para que `[(disabled)]` y compañía funcionen. Se listan aquí porque la sintaxis banana-in-a-box los oculta. |
opened / closed / cleared / viewChange (hub-datepicker) | EventEmitter | Eventos de ciclo de vida y navegación del calendario. |
onOpen / onClose / onClear / onSearch / onAdd / onRemove (hub-select) | EventEmitter | Eventos de ciclo de vida del dropdown y de tag/typeahead. |
onFocus / onBlur (hub-select) | EventEmitter<any> | Se emiten cuando el control dropdown gana o pierde el foco (formato dropdown), retransmitiendo los eventos focus/blur del proveedor. |
scroll / scrollToEnd (hub-select) | EventEmitter<{ start: number; end: number }> / EventEmitter<any> | scroll emite la ventana visible { start, end } mientras la lista del dropdown se desplaza; scrollToEnd emite cuando la lista llega a su final — el gancho para carga infinita/paginada con typeahead. |
enter (hub-input) | EventEmitter<number | string | boolean | File | FileList | null> | Emite el valor actual al pulsar Enter. |
completed (hub-otp-input) | EventEmitter<string> | Emite el código completo una vez que todas las celdas están rellenas. |
Templates
Hazlo tuyo — 10 plantillas para proyectar tu propio marcado.
| Nombre | Descripción | Ejemplo |
|---|---|---|
hubFormText | Proyecta contenido enriquecido de texto de ayuda. | <ng-template hubFormText>…</ng-template> |
hubValidationError | Sobrescribe el mensaje para una clave de error determinada. | <ng-template hubValidationError key="min">…</ng-template> |
hubLegend | Contenido personalizado de la leyenda del fieldset. | <ng-template hubLegend>…</ng-template> |
ng-option-tmp (hub-select) | Renderizado personalizado de las opciones del dropdown (directiva ng-select reexportada). | <ng-template ng-option-tmp let-item="item">…</ng-template> |
hubFileIcon (hub-file-input) | Icono por fichero para los que no tienen miniatura; recibe el elemento como contexto implícito. | <ng-template hubFileIcon let-item>…</ng-template> |
hubFilePreview (hub-file-input) | Sustituye el renderizado completo de un fichero seleccionado; recibe el elemento y las acciones de eliminar, reintentar y cancelar. | <ng-template hubFilePreview let-item let-remove="remove">…</ng-template> |
hubFileDropzoneNotice (hub-file-input) | Proyecta contenido arbitrario en la parte superior de la zona de soltar, sobre el icono — para un aviso que ni la invitación ni la pista de restricciones pueden expresar. | <p hubFileDropzoneNotice>2 documents still missing</p> |
hubSegmentedOption (hub-segmented) | Sustituye el contenido de cada segmento (iconos, badges, marcado enriquecido) mientras el componente sigue gestionando la selección, la navegación por teclado y ARIA. Contexto: la opción (implícita), selected e index. | <ng-template hubSegmentedOption let-option let-selected="selected" let-index="index">…</ng-template> |
hubSelectSuffix (hub-select, obsoleto) | Obsoleto desde 22.16.0: usa [hubAppend], que hace lo mismo en todos los campos. Sigue funcionando; [hubAppend] gana si están ambos. Acopla un control interactivo al borde final del select: un botón que actúa sobre lo seleccionado — configurarlo, consultarlo, crear uno nuevo. Se declara como plantilla y no como contenido proyectado porque el ng-content genérico del select transporta los ng-option hasta el motor y se lo tragaría; renderizar desde plantilla mantiene además la acción después del control en el DOM, así que el tabulador llega al campo antes que al botón que actúa sobre él. El control y la acción comparten un único borde y se leen como un solo campo. | <ng-template hubSelectSuffix><button …>…</button></ng-template> |
hubPrepend / hubAppend (all box-shaped fields) | Contenido acoplado al borde de un campo, más rico que el texto que puede llevar una cadena prepend / append: un icono, o un botón que actúa sobre el valor. Disponible en todos los campos que se dibujan como una caja con un valor — hub-input, hub-select, hub-textarea y hub-datepicker. Se combina con los addons de texto en lugar de sustituirlos: las cadenas se renderizan primero, así que lo proyectado queda siempre en el extremo de su lado — una unidad rotula el campo y la acción va más allá. Lo proyectado lleva el borde, el radio y la altura del campo, no los suyos, de modo que un botón no dibuja una segunda costura más gruesa junto al control. Se declara como plantilla porque el ng-content del campo ya está ocupado. Un slot también puede llevar otro campo —hub-input, hub-select, hub-textarea o hub-datepicker como hijo directo—, que cierra a ras con el que lo hospeda para que un precio y el periodo del que es precio se lean como la única afirmación que son. | <ng-template hubAppend><button …><hub-icon … /></button></ng-template> |