UI/UI
Loader
A simple and elegant loading spinner component with multiple sizes and color variants.
<div className="flex items-center gap-6 flex-wrap">
<Loader size="xs" />
<Loader size="sm" />
<Loader size="md" />
<Loader size="lg" />
<Loader size="xl" />
</div>
Installation
Install following dependencies:
npm install class-variance-authority
pnpm add class-variance-authority
yarn add class-variance-authority
bun add class-variance-authority
Copy and paste the following code into your project.
"use client";
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
const loaderVariants = cva("inline-block", {
variants: {
size: {
xs: "h-3 w-3",
sm: "h-4 w-4",
md: "h-5 w-5",
lg: "h-6 w-6",
xl: "h-8 w-8",
},
variant: {
default: "text-[hsl(var(--hu-foreground))]",
primary: "text-[hsl(var(--hu-primary))]",
secondary: "text-[hsl(var(--hu-secondary-foreground))]",
muted: "text-[hsl(var(--hu-muted-foreground))]",
},
},
defaultVariants: {
size: "md",
variant: "default",
},
});
export interface LoaderProps
extends React.SVGAttributes<SVGSVGElement>,
VariantProps<typeof loaderVariants> {}
const Loader = React.forwardRef<SVGSVGElement, LoaderProps>(
({ className, size, variant, ...props }, ref) => {
const [isMounted, setIsMounted] = React.useState(false);
React.useEffect(() => {
setIsMounted(true);
}, []);
return (
<svg
ref={ref}
className={cn(
loaderVariants({ size, variant }),
isMounted && "animate-spin",
className,
)}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
role="status"
aria-label="Loading"
suppressHydrationWarning
{...props}
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
/>{" "}
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
/>
</svg>
);
},
);
Loader.displayName = "Loader";
export { Loader, loaderVariants };
npx hextaui@latest add loader
pnpm dlx hextaui@latest add loader
yarn dlx hextaui@latest add loader
bun x hextaui@latest add loader
Usage
import { Loader } from "@/components/ui/Loader";
<Loader />
<Loader size="lg" />
<Loader variant="primary" />
<Loader size="sm" variant="muted" />
Examples
Sizes
Extra Small
Small
Medium
Large
Extra Large
<div className="flex items-center gap-6 flex-wrap">
<Loader size="xs" />
<Loader size="sm" />
<Loader size="md" />
<Loader size="lg" />
<Loader size="xl" />
</div>
Variants
Default
Primary
Secondary
Muted
<div className="flex items-center gap-6 flex-wrap">
<Loader variant="default" />
<Loader variant="primary" />
<Loader variant="secondary" />
<Loader variant="muted" />
</div>
With Loading Text
Loading...
Processing your request
Uploading files
Saving changes
<div className="space-y-4">
<div className="flex items-center gap-3">
<Loader size="sm" />
<span className="text-sm text-muted-foreground">Loading...</span>
</div>
<div className="flex items-center gap-3">
<Loader variant="primary" />
<span className="text-sm">Processing your request</span>
</div>
<div className="flex items-center gap-3">
<Loader size="sm" variant="muted" />
<span className="text-sm text-muted-foreground">Uploading files</span>
</div>
<div className="flex items-center gap-3">
<Loader variant="secondary" />
<span className="text-sm">Saving changes</span>
</div>
</div>
Button Integration
<div className="space-y-4">
<button
className="flex items-center gap-2 px-4 py-2 bg-primary text-primary-foreground rounded-[var(--radius)] hover:bg-primary/90 transition-colors disabled:opacity-50"
disabled
>
<Loader size="sm" className="text-current" />
<span>Loading...</span>
</button>
<button
className="flex items-center gap-2 px-4 py-2 bg-secondary text-secondary-foreground rounded-[var(--radius)] hover:bg-secondary/90 transition-colors disabled:opacity-50"
disabled
>
<Loader size="sm" className="text-current" />
<span>Processing</span>
</button>
<button
className="flex items-center gap-2 px-4 py-2 border border-border rounded-[var(--radius)] hover:bg-accent transition-colors disabled:opacity-50"
disabled
>
<Loader size="sm" />
<span>Uploading</span>
</button>
</div>
Content Loading States
Loading content...
Fetching data...
<div className="space-y-6">
<div className="border border-border rounded-2xl p-8">
<div className="flex items-center justify-center h-32">
<div className="text-center space-y-4">
<Loader size="xl" variant="primary" />
<p className="text-sm text-muted-foreground">Loading content...</p>
</div>
</div>
</div>
<div className="border border-border rounded-2xl p-6">
<div className="flex items-center justify-center h-24">
<div className="text-center space-y-3">
<Loader size="lg" variant="muted" />
<p className="text-xs text-muted-foreground">Fetching data...</p>
</div>
</div>
</div>
</div>
Inline Loading
Please wait while we process your request
Status:
Connecting...
Upload progress:
47% complete
<div className="space-y-4">
<div className="text-sm">
Please wait while we process your request{" "}
<Loader size="xs" className="inline-block align-text-bottom mx-1" />
</div>
<div className="flex items-center gap-2 text-sm">
<span>Status:</span>
<Loader size="xs" variant="primary" />
<span className="text-muted-foreground">Connecting...</span>
</div>
<div className="flex items-center gap-2 text-sm">
<span>Upload progress:</span>
<Loader size="xs" variant="secondary" />
<span className="text-muted-foreground">47% complete</span>
</div>
</div>
Props
Prop | Type | Default |
---|---|---|
className? | string | undefined |
variant? | "default" | "primary" | "secondary" | "muted" | "default" |
size? | "xs" | "sm" | "md" | "lg" | "xl" | "md" |
Edit on GitHub
Last updated on