Spinner y overlay de carga para Angular | ng-hub-ui-loading
Componente de carga para Angular con indicadores spinner, dots, bars, pulse y ring en modo inline, overlay y fullscreen, más un servicio para overlays bloqueantes de toda la aplicación.
Última actualización 16 sept 2026
Visión General
Por qué los equipos buscan esta librería
Usa ng-hub-ui-loading cuando una sección, un contenedor o la aplicación entera deba indicar que hay trabajo en curso, sin que cada vista se fabrique su propio spinner y su propia capa.
Instalación
npm install ng-hub-ui-loadingIr a
Ideal para
- carga de rutas y datos
- overlays al enviar formularios
- operaciones bloqueantes de toda la aplicación
- pantallas de arranque con marca
- barras de progreso de página bajo la navegación
Sobre loading
ng-hub-ui-loading es un componente standalone de Angular que representa un estado de carga indeterminado en tres modos: `inline` como bloque en el flujo del documento, `overlay` posicionado en absoluto sobre su contenedor padre y `fullscreen` fijado al viewport. Incluye cinco indicadores en CSS puro —spinner, dots, bars, pulse y ring— en tres tamaños, un mensaje opcional y una imagen de marca opcional animada con `none`, `spin` o `pulse`. `HubLoadingService` gobierna el overlay global a pantalla completa de forma programática y lleva un recuento de referencias de las llamadas concurrentes, de modo que dos peticiones en paralelo nunca se retiran el overlay la una a la otra. Cada color, tamaño y duración es una propiedad personalizada `--hub-loading-*`, con el mixin de Sass `hub-loading-theme()` para redefinir el conjunto; el componente es accesible de serie mediante `role=status`, `aria-live=polite` y `aria-busy`, y respeta `prefers-reduced-motion`. Junto a él, `hub-loading-bar` avisa de que la página misma está en camino: la franja fina bajo la barra de navegación, dibujada en el flujo del documento, anclada a una barra de navegación posicionada o fijada al viewport a la distancia de `--hub-loading-bar-offset`. `HubLoadingBarService` cuenta sus referencias igual, respeta un periodo de gracia para que el trabajo que acaba rápido no haga parpadear ninguna barra, y avanza hacia un final al que nunca llega por sí solo: solo `complete()` puede mostrar el 100 %. `provideHubLoadingBarRouter()` y `hubLoadingBarInterceptor` la conectan a la navegación y a HTTP sin que ninguno sepa del otro.
Guías de uso
Bloque inline
`inline` es el modo por defecto porque una región todavía vacía debería reservar ya el espacio que ocupará su contenido: el bloque participa en el flujo normal del documento, así que nada salta cuando llega el contenido real. `message` se renderiza bajo el indicador, y todo lo proyectado entre las etiquetas se renderiza bajo el mensaje — el sitio para una acción de cancelar o un aviso de que la operación está tardando más de lo habitual. El host lleva `role="status"`, `aria-live="polite"` y `aria-busy="true"`, de modo que un lector de pantalla recoge el mensaje al aparecer sin interrumpir lo que ya estaba leyendo.
Ejemplos:
Fundamentos del bloque inline
El bloque inline en sus tres formas útiles: solo indicador, indicador con mensaje, y un mensaje con una acción de cancelar proyectada debajo.
The block is announced as role="status" with aria-live="polite", so a screen reader reads the message when it appears without interrupting whatever is being read.
Código
Import:
Template:
Component:
Indicadores y acentos
La biblioteca incluye cinco indicadores puramente CSS — `spinner`, `dots`, `bars`, `pulse` y `ring` —, así que no arrastra ninguna imagen ni fuente de iconos. Tres pasos de tamaño preconfiguran `--hub-loading-size`, y el token sigue siendo sobrescribible por su cuenta cuando una maquetación necesita un tamaño que esos pasos no cubren. `color` no es un color CSS corriente: pasa por `resolveHubAccent()`, que interpreta un nombre suelto como `primary` como token del sistema de diseño y sigue el tema, mientras que un hex, un literal `oklch()` o una referencia `var(...)` se usan tal cual.
Ejemplos:
Variantes, tamaños y acentos
Los cinco indicadores incluidos, los tres pasos de tamaño y las tres formas que puede adoptar un acento — un nombre semántico, un literal de color CSS y una referencia `var(...)`.
Variants
spinnerdotsbarspulseringSizes
size="sm"size="md"size="lg" Each step is a preset for the --hub-loading-size token. Override that token directly when a layout needs a size the three steps do not cover.
Accents
color="primary"color="success"color="danger"color="#7c3aed"color="var(--hub-sys-color-warning)" A bare name resolves to var(--hub-sys-color-<name>) and tracks the active theme. A hex, an oklch() or a var(...) is used verbatim.
Código
Import:
Template:
Component:
Overlay y fullscreen
`overlay` cubre una región en lugar de la página. Se posiciona en absoluto, así que el ancestro posicionado más cercano decide qué queda cubierto — dale `position: relative` a ese contenedor o el overlay se escapa hacia arriba, hasta el ancestro que resulte estar posicionado. Acotarlo así mantiene el resto de la pantalla desplazable y utilizable. `fullscreen` queda fijado al viewport y es lo que `HubLoadingService` monta sobre `document.body`, fuera de todo subárbol de componentes, de forma que ningún `overflow` ni contexto de apilamiento de un ancestro puede recortarlo. Ambos modos pintan el velo translúcido salvo que se desactive `backdrop`.
Ejemplos:
Overlay de contenedor
Un overlay acotado a una tarjeta por el `position: relative` de esa misma tarjeta, dejando desplazable el resto de la página. Conmuta el backdrop para ver la diferencia entre un refresco en segundo plano y un trabajo que invalida lo que hay en pantalla.
Order #4821
3 items · delivered 14 Aug 2026
- Subtotal
- 212.00 €
- Shipping
- 9.90 €
- VAT (21%)
- 26.70 €
- Total
- 248.60 €
Turn the backdrop off to keep the content readable underneath — useful when the work is a background refresh rather than something that invalidates what is on screen.
Código
Import:
Template:
Component:
Servicio fullscreen
`HubLoadingService` gobernado desde TypeScript. Dos peticiones solapadas muestran por qué importa el contador de referencias: el primer `hide()` deja el overlay en pie porque el segundo llamante aún retiene una referencia, y `update()` reescribe el mensaje en pleno vuelo.
hideAll() after 5 seconds no matter what. Nothing yet.
Código
Import:
Template:
Component:
Marca y tematización
`image` cambia el indicador integrado por una marca propia, animada con `none`, `spin` o `pulse`: `spin` solo funciona bien sobre una marca radialmente simétrica, mientras que `pulse` mantiene un logotipo tipográfico derecho y legible. Todo lo visual vive en los tokens `--hub-loading-*`, declarados en `:where(.hub-loading)` para que cualquier ancestro pueda fijarlos — acento, tamaño, velocidad, grosor de trazo, separación, tamaño de imagen, color del texto y el tinte y desenfoque del backdrop. El mixin de Sass `hub-loading-theme()` fija toda la escalera de tokens en una sola llamada, y `provideHubLoading()` rebasa los valores por defecto de una aplicación entera sin tocar ninguna plantilla.
Ejemplos:
Imagen de marca
Una marca propia sustituye al indicador integrado y se muestra con las tres animaciones de imagen, para que se vea el compromiso entre `spin`, `pulse` y `none`.
imageAnimation="none"imageAnimation="spin"imageAnimation="pulse" Any URL works — an asset path, an imported file or, as here, an inline data URI. Size the mark with --hub-loading-image-size rather than size, which drives the built-in indicators.
Código
Import:
Template:
Component:
Tematización con variables CSS
Tematización en vivo mediante los tokens `--hub-loading-*` fijados en un elemento contenedor, incluidos el tinte y el desenfoque del backdrop, que solo hacen algo en los modos `overlay` y `fullscreen`.
Overlay preview
The backdrop tint and blur only apply in overlay and fullscreen modes. The tint is mixed from --hub-sys-surface-page, so it veils this text with the theme's own surface instead of a fixed colour — drop it to zero and the card stays fully legible underneath.
The same overrides written once, in Sass, are in the CSS tab — that is what hub-loading-theme() is for.
Código
Import:
Template:
Component:
Barra de progreso de página
`hub-loading-bar` es la franja fina que avisa de que la página misma está en camino: la que va bajo la barra de navegación. Tres decisiones la hacen creíble. Cuenta a quienes la piden, así que una navegación y las tres peticiones que lanza la página son cuatro referencias, y la barra termina con la última, no con la primera. Espera antes de pintar nada: el trabajo que acaba dentro del periodo de gracia no llega a mostrar barra, porque una ruta de 40 ms que hace parpadear un indicador de progreso se lee como un fallo, no como velocidad. Y su avance se frena a medida que se llena y se detiene antes del final: aquí nadie conoce el porcentaje real, de modo que solo `complete()` puede mostrar el 100 %, porque solo `complete()` sabe que es cierto. Colócala con `mode="overlay"` dentro de una barra de navegación posicionada, o con `mode="fixed"` y `--hub-loading-bar-offset` cuando la barra de navegación también está fijada.
Ejemplos:
Barra de progreso de página
La barra colgando de una barra de navegación simulada. Tres rutas muestran los tres comportamientos: una normal avanza, una lenta deja ver cómo el avance se frena, y una de 40 ms no llega a pintar barra alguna.
Orders
This page arrived without you watching a spinner.
Código
Import:
Template:
Component:
Progreso conocido y desconocido
Enlazar `progress` entrega la barra a quien la usa y publica `aria-valuenow`; `indeterminate` se desplaza en su lugar y retiene el valor. El tercer estado, `null`, la retira.
Known percentage
[progress]="null"A real value, so the bar announces it. Reaching 100% is the caller's call, not the trickle's.
No percentage at all
indeterminateA sweep instead of a fill, for a stream or a job that reports no stages. No value is announced, because there is none.
Both bars are mode="inline", so each reserves its own row and nothing on the card moves when a bar appears or goes away.
Código
Import:
Template:
Component:
Integración con router y HTTP
Por qué la barra cuenta a quienes la piden: una navegación más tres peticiones son cuatro referencias, y la barra termina con la última. El código muestra `provideHubLoadingBarRouter()`, el interceptor y la exclusión.
Nothing yet.
Código
Import:
Template:
Component:
Barrido de derecha a izquierda
La misma barra `indeterminate` bajo `dir="ltr"` y bajo `dir="rtl"`. El barrido se invierte con el texto, gobernado por `--hub-loading-bar-sweep-direction`, así que no hay que enlazar ni duplicar nada por idioma.
Loading results…
dir="ltr"Sweeps left to right, with the text.
جارٍ تحميل النتائج…
dir="rtl"يمسح من اليمين إلى اليسار، مع اتجاه النص.
The flip comes from [dir='rtl'] .hub-loading-bar, .hub-loading-bar[dir='rtl'], so the attribute counts wherever it sits — on <html>, on the region that changes direction, or on the <hub-loading-bar> element itself. The determinate fill needs no such treatment: it grows along the inline axis, which already reverses on its own.
Código
Import:
Template:
Component:
Características clave
Cambios recientes
Version 22.2.1 - 9/16/26, 12:00 AM
changed: Repository, issue and README links follow the move to the hub-env organization. Issues for every Hub UI package are now gathered in hub-env/hub-ui, and the repository and bugs fields of the manifest point at the new addresses. No code, types or styles change.
Version 22.2.0 - 9/8/26, 12:00 AM
changed: <hub-loading> and <hub-loading-bar> keep their stylesheets to themselves. Both shipped with ViewEncapsulation.None, and neither reason recorded for it held any more. Retheming from a global stylesheet is answered by the tokens, not by the encapsulation mode: they are declared on the host at zero specificity, a custom property inherits down to every element inside, and a rule written against .hub-loading still reaches the host because the class is on the host element. And the overlay HubLoadingService mounts on document.body is a real component instance created through createComponent(), so it carries its own stylesheet with it. See BREAKING_CHANGES.md.
changed: The bar's RTL rule is written as :host-context([dir='rtl']). It was a hand-written pair of selectors, one for the attribute on an ancestor and one for the attribute on the bar itself, because dir is inherited and both spellings are legitimate. :host-context() is exactly that pair, and under emulated encapsulation Angular now compiles it, which it never did while the component was unencapsulated. Same behaviour, one selector.
added: ng-hub-ui-ds is declared as an optional peer dependency (>=22.0.0). Both stylesheets have always resolved their defaults through the --hub-sys-* / --hub-ref-* ladder and the manifest said nothing about it, so a consumer reading the package on npm could not tell that installing the token package is what hands the indicator and the bar the family palette and its dark mode. It stays optional: every token carries a literal fallback and the library renders without it.
Version 22.1.1 - 9/6/26, 12:00 AM
added: Both READMEs now document the BEM classes of the loading bar and add a Right-to-left section explaining that the indeterminate sweep reverses under dir="rtl" so it travels with the text. Both have worked since 22.1.0 with nothing in the documentation to find them by, which is the same as not having them.
changed: rxjs is now declared as a peer dependency, because hubLoadingBarInterceptor imports finalize from it on the published path and a strict installer such as pnpm with hoisting turned off had no reason to resolve it. Nothing changes under npm or yarn, where rxjs arrives hoisted as a peer of @angular/core.
fixed: The Angular badge and the opening line of both READMEs say 21+, the range package.json has always declared. Claiming 22+ turned away an application on Angular 21 that the library supports.
fixed: HubLoadingService.isLoading is described as what it computes, the reference counter rather than the mounted overlay. The README contradicted itself, since its own SSR section already explained that on the server the counter runs while the mount is skipped.
fixed: FUNCTIONALITIES.md marks the ariaLabel of hub-loading as covered, which the Inline playground control has made true since the page shipped, and adds the RTL row of the bar so the file stops omitting behaviour the stylesheet has.
fixed: Calling HubLoadingService.hide(), HubLoadingBarService.complete() or HubLoadingBarService.inc() from inside an effect() no longer subscribes that effect to the internal state of the service. Each of those paths read a tracked signal to decide what to do next, the counter, whether the bar is on screen, the current fill, so the effect woke up on state it does not own: a show() from anywhere else re-ran it and retired a reference it never registered, and inc() re-entered itself on every step. The untracked read that already guarded the bar counter now covers the three places that were left out.
Version 22.1.0 - 9/5/26, 12:00 AM
added: hub-loading-bar: the thin page-progress strip that sits under the navbar, in three placements — inline in the flow, overlay against a positioned ancestor, or fixed to the viewport at --hub-loading-bar-offset.
added: HubLoadingBarService, with reference-counted start() / complete(), an anti-flicker grace period so fast work never paints a bar at all — set delay to 0 to opt out and reveal synchronously — and a trickle that decelerates as it fills and stops short of the end, since only complete() may show 100%.
added: provideHubLoadingBarRouter(), which runs the bar for the length of a navigation, including one a guard rejects, and hubLoadingBarInterceptor with withoutHubLoadingBar() to keep polls and heartbeats out of the count.
added: Determinate mode through the progress input, which publishes aria-valuenow, and an indeterminate sweep. Both withhold the value while the number is invented, which is how ARIA marks a progressbar of unknown position.
added: provideHubLoadingBar(), the HUB_LOADING_BAR_CONFIG token, the exported hubLoadingBarTrickle() curve, thirteen --hub-loading-bar-* tokens and the hub-loading-bar-theme() Sass mixin.
Version 22.0.0 - 8/24/26, 12:00 AM
added: Initial release of hub-loading: one component covering the inline block, the container overlay and the fullscreen layer, with role="status", aria-live="polite" and aria-busy set on the host.
added: Five pure-CSS indicators — spinner, dots, bars, pulse and ring — in three size steps, with no image or font dependency.
added: Accent resolution through resolveHubAccent() from ng-hub-ui-utils: a bare name becomes a --hub-sys-color-* token and follows the theme, while a hex, an oklch() or a var(...) is used verbatim.
added: Optional image input with none, spin and pulse animations, replacing the built-in indicator with a brand mark.
added: HubLoadingService for the fullscreen overlay, with a reference counter so concurrent callers cannot unblock the screen out from under each other, plus update() to re-dress the live overlay and hideAll() to force the count to zero. SSR-safe: a no-op without a DOM.
added: provideHubLoading() and the HUB_LOADING_CONFIG token, supplying application-wide defaults to both the component and the service.
added: Theming through the --hub-loading-* token ladder and the hub-loading-theme() Sass mixin, shipped at ng-hub-ui-loading/styles.
Librerías relacionadas
Preguntas frecuentes
¿Cómo se muestra un spinner u overlay de carga en Angular?
Instala ng-hub-ui-loading y representa `<hub-loading>` mientras el trabajo está en curso. Por defecto es un bloque inline en el flujo del documento; pon `mode` a `overlay` para cubrir el contenedor que lo rodea, o a `fullscreen` para bloquear el viewport. Para un overlay de toda la aplicación, inyecta `HubLoadingService` y llama a `show()` y `hide()` alrededor de la operación.
¿Conviene usar un spinner, un esqueleto o una barra de progreso?
Recurre a ng-hub-ui-skeleton cuando ya conozcas la forma del contenido que viene, porque el marcador reserva el espacio y evita el salto de maquetación. Usa ng-hub-ui-loading cuando la espera sea indeterminada o haya que bloquear la pantalla: un formulario que se envía, un informe que se genera. Cuando puedas informar de un avance real, ng-hub-ui-metrics dibuja barras, medidores y anillos determinados.
¿Cómo se cambia el color del indicador de carga de Angular?
Usa el input `color`, que admite un nombre semántico, un hex, un valor `oklch()` o una referencia `var(...)` a uno de tus tokens. Para un cambio permanente, cada color, tamaño y duración es una propiedad personalizada `--hub-loading-*` que puedes redefinir desde tu propia hoja de estilos, y el mixin de Sass `hub-loading-theme()` reestiliza el componente entero en un solo sitio. El input `image` sustituye el indicador por un logo cuando el estado de carga deba llevar la marca.
¿Es accesible y compatible con SSR el componente de carga de Angular?
Sí. El host es una región viva —`role=status`, `aria-live=polite` y `aria-busy`— con un input `ariaLabel` para el texto que se anuncia, y todas las animaciones se desactivan bajo `prefers-reduced-motion`. En el servidor no hay DOM en el que montar, así que `HubLoadingService` guarda solo su contador y el renderizado en servidor sigue siendo seguro.
¿Cómo se añade una barra de carga de página bajo la barra de navegación en Angular?
Representa `<hub-loading-bar mode="overlay" placement="bottom">` dentro de una barra de navegación con `position: relative`, o usa `mode="fixed"` con `--hub-loading-bar-offset` cuando la barra de navegación también esté fijada. Después añade `provideHubLoadingBarRouter()` para que la barra dure lo que dure cada navegación, incluida una que rechace un guard, y `hubLoadingBarInterceptor` para que cubra también las peticiones que la página lanza al llegar. La barra cuenta las referencias de quienes la piden, así que ambas cosas se componen sin que ninguna sepa de la otra, y `withoutHubLoadingBar()` mantiene los sondeos en segundo plano fuera de la cuenta.