Loading data after a click
Animate data loading in React with LoadCut and ValueCut, using React Query, SWR or plain fetch, so a click never makes the page jump.
There are two moments to cover: the first load, when a skeleton becomes content, and every refetch after it, when values change in place.
First load: LoadCut
Pass the library's loading flag straight to loading:
import { useQuery } from "@tanstack/react-query"
import { LoadCut } from "@/components/keyframery/load-cut"
import { Skeleton } from "@/components/ui/skeleton"
export function Revenue() {
const { data, isPending } = useQuery({ queryKey: ["revenue"], queryFn: fetchRevenue })
return (
<LoadCut loading={isPending} skeleton={<Skeleton className="h-40" />}>
{data && <RevenueChart data={data} />}
</LoadCut>
)
}With SWR, use isLoading. With fetch in an effect, use your own loading state.
Make the skeleton roughly the size of the content. LoadCut morphs the height between them, but the closer they are, the calmer the change.
Refetches: ValueCut
After the first load, don't show the skeleton again for a refetch. Keep the old values on screen and let them change in place:
<ValueCut value={data.total} format={{ style: "currency", currency: "USD" }} />Changing a filter
When a filter changes and the old content no longer applies (a different date range, say), set loading while the new data loads. If it comes back within 300 ms, the skeleton never shows. The dashboard on the home page does exactly this.
Speed, easing and cuts
Tune shadcn/ui animations like colours: CSS variables set speed and easing, <Cuts> props pick each component's cut, and attributes change one element.
Detail pages on their own route
Animate a card on one route into its detail page on another in the Next.js App Router with MatchCut. Going back shrinks the detail into the card again.