Loading state components for blocking operations, animated loaders, and top-of-page progress indicators.
Inspired by Mantine LoadingOverlay, Ant Design Spin, and the NProgress top-bar pattern used by GitHub, YouTube, and other major SaaS products.
Pure CSS — no JavaScript hooks required.
Sub-components
| Component | Purpose |
|---|---|
loading_overlay/1 | Semi-transparent overlay blocking container/page interactions |
loading_dots/1 | Three-dot bounce animation (alternative to spinner) |
loading_bar/1 | Slim animated top-of-page progress bar (NProgress style) |
Loading overlay (scoped to a container)
<div class="relative">
<.loading_overlay visible={@loading} label="Saving changes..." />
<.form ...>...</.form>
</div>Loading overlay (full screen)
<.loading_overlay visible={@initializing} fullscreen label="Initializing..." />Bouncing dots
<div class="flex items-center gap-2">
<.loading_dots />
<span class="text-sm text-muted-foreground">Processing...</span>
</div>Top progress bar (root layout)
<%!-- In root.html.heex, shown while navigating --%>
<.loading_bar :if={@loading} />
Summary
Functions
Renders a slim indeterminate progress bar at the top of the page.
Renders three animated bouncing dots as a loading indicator.
Renders a semi-transparent overlay that blocks user interaction during loading.
Functions
Renders a slim indeterminate progress bar at the top of the page.
Inspired by the NProgress library used by GitHub, YouTube, and other apps. Place at the very top of the viewport (before the main layout) and toggle visibility via a LiveView assign during navigation or long operations.
The bar runs a shimmer animation indefinitely until removed from the DOM.
Example
<%!-- In root.html.heex --%>
<.loading_bar :if={@page_loading} />
<header>...</header>
<main>...</main>Attributes
class(:string) - Additional CSS classes for the bar. Defaults tonil.- Global attributes are accepted. HTML attrs forwarded to the root
<div>.
Renders three animated bouncing dots as a loading indicator.
Use as an alternative to Spinner when a more playful or compact loader
is appropriate — typing indicators, inline "thinking" states, chat messages.
Each dot staggers its bounce animation for a fluid wave effect.
Example
<%!-- Inline beside text --%>
<div class="flex items-center gap-2 text-muted-foreground">
<.loading_dots size={:sm} />
<span class="text-sm">AI is thinking...</span>
</div>Attributes
size(:atom) - Size of the dots. Defaults to:default. Must be one of:sm,:default, or:lg.label(:string) - Screen-reader-only label. Defaults to"Loading".class(:string) - Additional CSS classes. Defaults tonil.- Global attributes are accepted. HTML attrs forwarded to the wrapper
<span>.
Renders a semi-transparent overlay that blocks user interaction during loading.
For scoped containers (a card, a form section), place this as the first child
inside a position: relative parent. For full-page blocking, set fullscreen={true}.
Example
<%!-- Scoped to a card --%>
<div class="relative rounded-lg border p-6">
<.loading_overlay visible={@saving} label="Saving..." show_label />
<.card_content>...</.card_content>
</div>
<%!-- Full-page during initial data load --%>
<.loading_overlay visible={@loading} fullscreen />Attributes
visible(:boolean) - Whenfalse, the overlay is not rendered. Defaults totrue.label(:string) - Accessible label — announced by screen readers and shown below the spinner whenshow_labelis true. Defaults to"Loading...".show_label(:boolean) - Whentrue, displays the label text below the spinner. Defaults tofalse.fullscreen(:boolean) - Whentrue, usesfixed inset-0to cover the entire viewport. Whenfalse(default), usesabsolute inset-0to cover the nearestposition: relativeancestor. Defaults tofalse.blur(:boolean) - Whentrue, applies a subtle backdrop blur to the underlying content. Defaults tofalse.class(:string) - Additional CSS classes for the overlay. Defaults tonil.- Global attributes are accepted. HTML attrs forwarded to the overlay
<div>.