Get Started
Migration
Components
- Accordion
- Alert Dialog
- Alert
- Aspect Ratio
- Avatar
- Badge
- Breadcrumb
- Button Group
- Button
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Collapsible
- Combobox
- Command
- Context Menu
- Data Table
- Date Picker
- Dialog
- Drawer
- Dropdown Menu
- Empty
- Field
- Formsnap
- Hover Card
- Input Group
- Input OTP
- Input
- Item
- Kbd
- Label
- Menubar
- Navigation Menu
- Pagination
- Popover
- Progress
- Radio Group
- Range Calendar
- Resizable
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toggle Group
- Toggle
- Tooltip
- Typography
Installation
Special sponsor
We're looking for one partner to be featured here.
Support the project and reach thousands of developers.
Reach outProcessing payment...
$100.00
<script lang="ts">
import { Spinner } from "$lib/components/ui/spinner/index.js";
import * as Item from "$lib/components/ui/item/index.js";
</script>
<div class="flex w-full max-w-xs flex-col gap-4 [--radius:1rem]">
<Item.Root variant="muted">
<Item.Media>
<Spinner />
</Item.Media>
<Item.Content>
<Item.Title class="line-clamp-1">Processing payment...</Item.Title>
</Item.Content>
<Item.Content class="flex-none justify-end">
<span class="text-sm tabular-nums">$100.00</span>
</Item.Content>
</Item.Root>
</div>
Installation
pnpm dlx shadcn-svelte@latest add spinner
npx shadcn-svelte@latest add spinner
bun x shadcn-svelte@latest add spinner
npx shadcn-svelte@latest add spinner
Install @lucide/svelte
:
pnpm i @lucide/svelte -D
npm i @lucide/svelte -D
bun install @lucide/svelte -D
yarn install @lucide/svelte -D
Copy and paste the component source files linked at the top of this page into your project.
Usage
<script lang="ts">
import { Spinner } from "$lib/components/ui/spinner/index.js";
</script>
<Spinner />
Customization
You can replace the default spinner icon with any other icon by editing the Spinner component.
<script lang="ts">
import { cn } from "$lib/utils.js";
import LoaderIcon from "@lucide/svelte/icons/loader";
import type { ComponentProps } from "svelte";
type Props = ComponentProps<typeof LoaderIcon>;
let { class: className, ...restProps }: Props = $props();
</script>
<LoaderIcon
role="status"
aria-label="Loading"
class={cn("size-4 animate-spin", className)}
{...restProps}
/>
Examples
Size
Use the size-*
utility class to change the size of the spinner.
<script lang="ts">
import { Spinner } from "$lib/components/ui/spinner/index.js";
</script>
<div class="flex items-center gap-6">
<Spinner class="size-3" />
<Spinner class="size-4" />
<Spinner class="size-6" />
<Spinner class="size-8" />
</div>
Color
Use the text-*
utility class to change the color of the spinner.
<script lang="ts">
import { Spinner } from "$lib/components/ui/spinner/index.js";
</script>
<div class="flex items-center gap-6">
<Spinner class="size-6 text-red-500" />
<Spinner class="size-6 text-green-500" />
<Spinner class="size-6 text-blue-500" />
<Spinner class="size-6 text-yellow-500" />
<Spinner class="size-6 text-purple-500" />
</div>
Button
Add a spinner to a button to indicate a loading state. The <Button />
will handle the spacing between the spinner and the text.
<script lang="ts">
import { Button } from "$lib/components/ui/button/index.js";
import { Spinner } from "$lib/components/ui/spinner/index.js";
</script>
<div class="flex flex-col items-center gap-4">
<Button disabled size="sm">
<Spinner />
Loading...
</Button>
<Button variant="outline" disabled size="sm">
<Spinner />
Please wait
</Button>
<Button variant="secondary" disabled size="sm">
<Spinner />
Processing
</Button>
</div>
Badge
You can also use a spinner inside a badge.
Syncing Updating Processing
<script lang="ts">
import { Badge } from "$lib/components/ui/badge/index.js";
import { Spinner } from "$lib/components/ui/spinner/index.js";
</script>
<div class="flex items-center gap-4 [--radius:1.2rem]">
<Badge>
<Spinner />
Syncing
</Badge>
<Badge variant="secondary">
<Spinner />
Updating
</Badge>
<Badge variant="outline">
<Spinner />
Processing
</Badge>
</div>
Input Group
Input Group can have spinners inside <InputGroup.Addon>
.
Validating...
<script lang="ts">
import * as InputGroup from "$lib/components/ui/input-group/index.js";
import { Spinner } from "$lib/components/ui/spinner/index.js";
import ArrowUpIcon from "@lucide/svelte/icons/arrow-up";
</script>
<div class="flex w-full max-w-md flex-col gap-4">
<InputGroup.Root>
<InputGroup.Input placeholder="Send a message..." disabled />
<InputGroup.Addon align="inline-end">
<Spinner />
</InputGroup.Addon>
</InputGroup.Root>
<InputGroup.Root>
<InputGroup.Textarea placeholder="Send a message..." disabled />
<InputGroup.Addon align="block-end">
<Spinner /> Validating...
<InputGroup.Button class="ml-auto" variant="default">
<ArrowUpIcon />
<span class="sr-only">Send</span>
</InputGroup.Button>
</InputGroup.Addon>
</InputGroup.Root>
</div>
Empty
Processing your request
Please wait while we process your request. Do not refresh the page.
<script lang="ts">
import * as Empty from "$lib/components/ui/empty/index.js";
import { Spinner } from "$lib/components/ui/spinner/index.js";
import { Button } from "$lib/components/ui/button/index.js";
</script>
<Empty.Root class="w-full">
<Empty.Header>
<Empty.Media variant="icon">
<Spinner />
</Empty.Media>
<Empty.Title>Processing your request</Empty.Title>
<Empty.Description>
Please wait while we process your request. Do not refresh the page.
</Empty.Description>
</Empty.Header>
<Empty.Content>
<Button variant="outline" size="sm">Cancel</Button>
</Empty.Content>
</Empty.Root>
Item
Use the spinner inside <Item.Media>
to indicate a loading state.
Downloading...
129 MB / 1000 MB
<script lang="ts">
import * as Item from "$lib/components/ui/item/index.js";
import { Spinner } from "$lib/components/ui/spinner/index.js";
import { Button } from "$lib/components/ui/button/index.js";
import { Progress } from "$lib/components/ui/progress/index.js";
</script>
<div class="flex w-full max-w-md flex-col gap-4 [--radius:1rem]">
<Item.Root variant="outline">
<Item.Media variant="icon">
<Spinner />
</Item.Media>
<Item.Content>
<Item.Title>Downloading...</Item.Title>
<Item.Description>129 MB / 1000 MB</Item.Description>
</Item.Content>
<Item.Actions class="hidden sm:flex">
<Button variant="outline" size="sm">Cancel</Button>
</Item.Actions>
<Item.Footer>
<Progress value={75} />
</Item.Footer>
</Item.Root>
</div>