Fluxon.Components.Loading (Fluxon v3.1.2)

Provides <.loading> component for inline loading indicators built from animated SVG.

The loading component renders a single inline SVG sized and colored through Tailwind utilities on the standard class attribute. Each variant uses a CSS keyframe animation defined in the design system, so the indicator runs without JavaScript and remains in sync with the document's frame rate.

Usage

Render the indicator with no attributes for the default rotating ring at size-5:

<.loading />

Pick a variant that matches the context, then layer Tailwind utilities for size and color:

<.loading variant="dots-bounce" class="size-6 text-primary" />

Tune the animation speed with duration when the default cadence reads as too fast or too slow for the surrounding UI:

<.loading variant="bars-scale" duration={900} />

Variants

Each variant draws a different shape and applies its own keyframe animation. The visual family (ring, dots, bars) sets the overall character, and the suffix describes the motion.

<.loading variant="ring" />
<.loading variant="ring-bg" />
<.loading variant="dots-bounce" />
<.loading variant="dots-fade" />
<.loading variant="dots-scale" />
<.loading variant="bars-fade" />
<.loading variant="bars-scale" />
<.loading variant="bars-scale-fade" />
VariantShapeMotionUse Case
ringOpen arcRotatesDefault indicator for buttons and inline status
ring-bgOpen arc over full ringRotates over a faint trackSame as ring when the background needs more contrast
dots-bounceThree horizontal dotsBounce vertically in sequenceCasual or playful surfaces, chat or assistant interfaces
dots-fadeThree horizontal dotsFade in and out in sequenceSubtle background tasks where motion should not draw the eye
dots-scaleThree horizontal dotsScale in and out in sequenceMid-emphasis indicator when the dots-fade pattern feels too quiet
bars-fadeThree wide barsFade in sequenceProcessing indicators in dense layouts (tables, list rows)
bars-scaleFive thin barsScale vertically in sequenceAudio or media contexts where an equalizer reads as natural
bars-scale-fadeThree full-height barsCombined scale and fadeHigh-emphasis loading states that need a richer rhythm

Sizing

The default size is size-5. Override it by passing any Tailwind sizing utility through class; the SVG scales proportionally because every variant uses a 0 0 24 24 view box.

<.loading class="size-3" />
<.loading class="size-5" />
<.loading class="size-8" />
<.loading class="size-12" />
Size classPixel sizeUse Case
size-312 pxInside compact badges or input affixes
size-416 pxInline with body text or button labels
size-520 pxDefault, suitable for most buttons and form rows
size-624 pxSection-level loading regions
size-8+32 px and upPage-level loading states centered in empty regions

Color

The indicator draws with currentColor, so any Tailwind text-* utility in class sets the visible color. The default tone is text-foreground-soft, which sits between primary text and muted text on both light and dark themes.

<.loading class="text-foreground" />
<.loading class="text-primary" />
<.loading class="text-success" />
<.loading class="text-danger" />
<.loading class="text-white" />

Inside a colored solid button, set the color to match the foreground of the surrounding surface so the indicator stays legible:

<.button variant="solid" color="primary" disabled>
  <.loading class="size-4 text-white" /> Saving
</.button>

Animation Speed

duration sets the length of one full animation cycle in milliseconds and applies to every keyframe in the variant. The default of 600 ms reads as energetic without feeling frantic. Lower values produce a tighter, more urgent feel; higher values produce a calmer, ambient indicator.

<.loading duration={300} />
<.loading duration={600} />
<.loading duration={1200} />

Multi-element variants stagger off duration

For the dots-* and bars-* variants, each element's animation delay is computed as a fraction of duration. Changing duration changes the cadence of the whole sequence, not just the speed of one element.

Accessible name

By default the indicator is decorative: it renders with aria-hidden and carries no accessible name. This is the right choice when adjacent visible text already describes the pending task, for example a button that reads "Saving..." or a status row labeled "Syncing latest changes". The animation is redundant with that text, so hiding it keeps the output uncluttered.

When the indicator stands alone with no surrounding text, pass label so it renders as a status region with an accessible name:

<.loading label="Loading results" class="size-8" />

Use label for standalone, page-level, or overlay loaders. Omit it whenever a visible caption already communicates what is loading.

Examples

Loading button

Combine with Fluxon.Components.Button to show in-flight form submissions or async actions. Disabling the button while the request is pending prevents duplicate submits:

<.button type="submit" variant="solid" color="primary" disabled={@saving}>
  <.loading :if={@saving} class="size-4 text-white" />
  {if @saving, do: "Saving...", else: "Save changes"}
</.button>

Centered page loader

Use a larger size on a flex container to fill an empty region while data loads. Because no visible caption accompanies it, pass label to give the standalone loader a name:

<div class="flex min-h-[400px] items-center justify-center">
  <.loading variant="ring-bg" class="size-10" label="Loading" />
</div>

Overlay over an existing section

Stack the indicator above content that is being refreshed without unmounting the underlying markup:

<div class="relative">
  <div
    :if={@refreshing}
    class="absolute inset-0 flex items-center justify-center bg-background/70 backdrop-blur-sm"
  >
    <.loading class="size-6" />
  </div>
  <.table rows={@rows}>
    <!-- ... -->
  </.table>
</div>

Inline status next to a label

Pair with body text inside list rows or status panels:

<div class="flex items-center gap-2 text-sm text-foreground-soft">
  <.loading variant="dots-fade" class="size-4" />
  Syncing latest changes
</div>

Streamed LiveView state

Toggle the indicator off when the corresponding stream finishes loading on the server:

<div :if={@status == :loading} class="flex items-center gap-2">
  <.loading variant="bars-scale" class="size-5 text-primary" />
  <span>Crunching numbers</span>
</div>

Summary

Components

Renders an animated SVG loading indicator.

Components

loading(assigns)

Renders an animated SVG loading indicator.

Use this component anywhere a task is in flight and the user is waiting for a result: inside buttons during form submission, in section overlays while data refreshes, or as a centered page-level placeholder. The variant chooses the visual treatment, while class controls size and color through standard Tailwind utilities.

Attributes

  • class (:any) - Extra Tailwind classes appended to the rendered <svg> element. Use sizing utilities (size-4, size-6, ...) and text-color utilities (text-primary, text-white, ...) to override the defaults. Without overrides the SVG renders at size-5 with the text-foreground-soft color token.

    Defaults to nil.

  • duration (:integer) - Length of one complete animation cycle in milliseconds. Applied uniformly to every animated element in the variant; for multi-element variants (dots-* and bars-*), individual delays are computed as fractions of this value so the staggered cadence scales with duration. Defaults to 600.

    Defaults to 600.

  • label (:string) - Sets an accessible name for the indicator and renders it as a status region. Provide a label for standalone loaders, page-level placeholders, or overlays where no adjacent visible text describes the pending task. When omitted (the default), the indicator renders as decorative with aria-hidden, which is the right choice when nearby text already communicates what is loading. Defaults to nil.

    Defaults to nil.

  • variant (:string) - The visual style of the indicator. Defaults to "ring".

    • ring: rotating open arc. Default, suitable for most inline loading states.
    • ring-bg: rotating arc layered over a faint full ring. Use when the indicator sits on a busy or low-contrast background and the open ring needs a track behind it.
    • dots-bounce: three horizontal dots that bounce vertically in sequence. Use on casual or conversational surfaces where the playful motion fits the tone.
    • dots-fade: three horizontal dots that fade in and out in sequence. Use for passive background tasks where the indicator should not draw the eye.
    • dots-scale: three horizontal dots that grow and shrink in sequence. Use as a mid-emphasis alternative to dots-fade when the indicator should feel more present.
    • bars-fade: three wide bars that fade in sequence. Use as a compact processing indicator inside dense layouts like tables or list rows.
    • bars-scale: five thin bars that scale vertically in sequence. Use in audio, recording, or media playback contexts where an equalizer pattern reads as natural.
    • bars-scale-fade: three full-height bars that scale and fade together. Use when the loading state is the focal point of the surface and needs a richer rhythm.

    Defaults to "ring". Must be one of "ring", "ring-bg", "dots-bounce", "dots-fade", "dots-scale", "bars-fade", "bars-scale", or "bars-scale-fade".