HextaUI

Spinner: Without flicker

Pass loading and the spinner waits delay (150ms) before showing, so fast loads never flash it, then stays at least minDuration (400ms) once it's visible.

"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import { Spinner } from "@/components/ui/spinner"

export function SpinnerDelayed() {
  const [loading, setLoading] = React.useState(false)

  const load = (ms: number) => {
    setLoading(true)
    setTimeout(() => setLoading(false), ms)
  }

  return (
    <div className="flex max-w-full min-w-0 flex-col items-center gap-4">
      <div className="flex size-8 items-center justify-center">
        <Spinner loading={loading} size="lg" />
      </div>
      <div className="flex flex-wrap justify-center gap-2">
        <Button variant="outline" size="sm" onClick={() => load(100)}>
          Fast load (100ms)
        </Button>
        <Button variant="outline" size="sm" onClick={() => load(250)}>
          Load (250ms)
        </Button>
        <Button variant="outline" size="sm" onClick={() => load(2000)}>
          Slow load (2s)
        </Button>
      </div>
    </div>
  )
}

This adds the example as components/examples/spinner/delayed.tsx, together with the Spinner component and the HextaUI theme tokens it needs.

pnpm dlx shadcn@latest add https://hextaui.com/r/spinner-delayed.json

To add only the component, follow the Spinner installation.

Props in this example

The Spinner props this example sets, from the API reference.

PropTypeDefault
sizenull leaves sizing to the parent.
"sm" | "default" | "lg" | "xl" | null"default"
loadingTurns on delayed showing. Leave it out to always show.
boolean–

Every prop is in the Spinner API reference.

See them all, with keyboard support and accessibility notes, on the Spinner page.