Loading Swap
Swaps child content with a loading spinner without changing the element size.
"use client"
import { Button } from "@/components/ui/button"import { LoadingSwap } from "@/components/ui/loading-swap"import { useTransition } from "react"
export function LoadingButton() { const [isLoading, startTransition] = useTransition()
return ( <Button onClick={() => { startTransition(async () => { // Simulate loading state await new Promise(res => setTimeout(res, 1000)) }) }} > <LoadingSwap isLoading={isLoading}>Click Me</LoadingSwap> </Button> )}
Installation
Section titled “Installation”Copy and paste the following code into your project.
components/ui/loading-swap.tsx
import { cn } from "@/lib/utils"import { Loader2Icon } from "lucide-react"import type { ReactNode } from "react"
export function LoadingSwap({ isLoading, children, className,}: { isLoading: boolean children: ReactNode className?: string}) { return ( <div className="grid grid-cols-1 items-center justify-items-center"> <div className={cn( "col-start-1 col-end-2 row-start-1 row-end-2 w-full", isLoading ? "invisible" : "visible", className, )} > {children} </div> <div className={cn( "col-start-1 col-end-2 row-start-1 row-end-2", isLoading ? "visible" : "invisible", className, )} > <Loader2Icon className="animate-spin" /> </div> </div> )}
Update the import paths to match your project setup.
import { LoadingSwap } from "@/components/ui/loading-swap"
<LoadingSwap isLoading>Search</LoadingSwap>
Examples
Section titled “Examples”Large components
Section titled “Large components”"use client"
import { Button } from "@/components/ui/button"import { Card, CardDescription, CardHeader, CardTitle,} from "@/components/ui/card"import { LoadingSwap } from "@/components/ui/loading-swap"import { useState } from "react"
export function LoadingButton() { const [isLoading, setIsLoading] = useState(false)
return ( <div className="flex flex-col gap-2"> <Button onClick={() => setIsLoading(l => !l)} className="w-fit"> Toggle Loading </Button> <Card className="w-96"> <LoadingSwap isLoading={isLoading}> <CardHeader> <CardTitle>Larger Component</CardTitle> <CardDescription> Can be used to wrap any components </CardDescription> </CardHeader> </LoadingSwap> </Card> </div> )}