Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Feedback

Spinner

Feedback

Spinner React component for Tailwind CSS v4

SkeletonToast
Live props
Appearance
variant
size
tone
color
track
Behavior
speed1x
delay0ms
Content
label
showLabel
Layout
labelPosition
State
paused
Code
import { Spinner } from "@/components/ui/spinner"

<Spinner />
  1. Home
  2. Components
  3. Feedback
  4. Spinner
Free

Spinner React component for Tailwind CSS v4

v1.0.0·Added in 1.0.0

A React loading spinner for waits without a known shape: six styles, from a quiet ring to the iOS spokes, in any size, tone or speed.

It turns on its own and never takes focus. Screen readers hear its label once, as a polite status, and nothing else; inside a parent that already announces the wait (a loading button) pass aria-hidden and it stays silent. With a delay it stays invisible for fast loads and fades in only when the wait gets long enough to notice. Under reduced motion it keeps turning at half speed, so the page still reads as busy. Every style animates only transform and opacity on the compositor, so it keeps moving while the page is busy.

Spinner is a free React component in the React feedback components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add spinner, together with UIProvider and Tones.

Add to a project

Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add spinner

Usage

Import Spinner from @/components/ui/spinner.

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

export function ListingsLoading() {
  return (
    <div className="flex flex-col items-center gap-3 py-12 text-muted-foreground">
      <Spinner variant="spokes" size="lg" delay={300} label="Loading listings" />
      <p className="text-sm">Searching apartments in New York…</p>
    </div>
  )
}

Props

  • variantdefault "ring"
    "ring" | "dots" | "bars" | "pulse" | "orbit" | "spokes"

    ring: a quarter arc over a faint track. dots: three dots in a wave. bars: three bars like an equalizer. pulse: a dot with an expanding ring. orbit: two dots circling. spokes: the iOS activity indicator, 8 spokes (12 from 40px) with the light traveling clockwise.

  • sizedefault "md"
    "sm" | "md" | "lg" | number

    16 / 24 / 40px, or any px number (12 at least). sm for inline text and buttons, md for cards and panels, lg for a whole page. The ring stroke and the label grow with it.

  • tonedefault "current"
    "current" | "neutral" | "brand" | "success" | "warning" | "danger" | "info"

    current follows the text color, so it works inside any colored parent (a solid button, a colored chip). A tone paints the indicator with the design tokens and the visible label with the readable tone text.

  • colordefault ""
    string

    Any CSS color. Replaces the tone; faded parts use the same color at lower opacity. Leave empty to use the tone.

  • speeddefault 1
    number

    Playback multiplier: 0.5 is half speed, 2 twice as fast. Clamped to 0.25 to 4. Every style keeps its own rhythm (ring 0.75s, spokes 0.8s, dots 1s per loop).

  • labeldefault "Loading"
    string

    The accessible name, announced once as a polite status. Shown next to the indicator with showLabel. Pass aria-hidden when a parent already announces the loading (a loading button): the spinner then drops its status role and this label.

  • showLabeldefault false
    boolean

    Shows the label next to (or under) the indicator. Without it the label is only for screen readers.

  • labelPositiondefault "end"
    "end" | "bottom"

    end sits beside the indicator for inline use; bottom stacks it, for page and panel loaders.

  • trackdefault true
    boolean

    Ring only: the faint full circle under the arc. Turn it off for a lighter look on busy backgrounds.

  • delaydefault 0
    number

    Milliseconds before anything renders, label included, counted from mount. 300 hides the spinner entirely for fast loads, so it never flashes; after the wait it fades in. A spinner that is already showing never hides again when delay changes (remount it with a key to replay the wait).

  • pauseddefault false
    boolean

    Holds the current frame. Useful while a pull-to-refresh is still being dragged, or for a still in a gallery.

  • classNames
    Partial<Record<"indicator" | "label", string>>

    Extra classes for the drawing (svg or span) and the label.

  • className
    string

    Extra classes for the root span, merged last. Override the color with [--spinner-color:...].

  • style
    CSSProperties

    Inline styles for the root span.

Examples

Six styles

ring, dots, bars, pulse, orbit and spokes at the default md size.

Sizes

sm 16, md 24, lg 40 or any px number. Spokes switch to 12 from 40px.

Tones and custom color

Six tones, a custom violet, and current color inside a brand chip and a loading button.

Inline and in rows

An sm autosave spinner with its label beside a title, and one trailing a list row in the muted text color.

Delay

Both use delay={300}. The 200 ms request finishes before the spinner would show, so it never flashes.

Page loader

lg spokes with the label stacked under it, for a whole screen that is waiting.

Pull to refresh

Drag the list down: the paused spokes wind up with your finger and start spinning when you let go.

Speed

A multiplier on each style's own rhythm: 0.5, 1 and 2.

Dependencies

ui-configtones

Files

  • components/ui/spinner.tsx

FAQ

Is the React Spinner component free?

Yes. The source is free and needs no account: copy it from the Code tab or install it with the CLI.

How do I install Spinner?

Run npx wingo-ui@latest add spinner. It also adds the Wingo UI items it builds on (UIProvider and Tones). With shadcn, run npx shadcn@latest add https://wingo-ui.com/r/spinner.json.

See also

SkeletonProgressRoute ProgressPull To RefreshButtonToneslib

Used in

Image LightboxVideo PlayerSwitchWorkflow CanvasVoice InputSlide To ConfirmUser MenuToastAudio PlayerModel PickerQuantity stepperCoupon input

and 24 more.

More React feedback components

Emoji ReactionAlertBannerCookie ConsentEmpty StateNotification Bell
All 13 React feedback components

Articles using this component

  • React Skeleton Loader: Real Shapes, No Layout Shift

    Component guides · Oct 19, 2026 · 9 min read

PreviousSkeletonNext Toast

Apartments for rent

New York · 2 bedrooms · Upper West Side

1,284
Loading

Loading listings in New York…

Searching 1,284 new offers

delay 0ms · 1x

Changing the delay or pressing Reload replays the wait