Loaders
Car Loader
A sharp, flat 2D RC car loading spinner. The car drives back and forth across a dashed road with spinning wheels, fading out smoothly at the edges instead of a hard clip.
Loading preview
Advertisement
Ad space reserved for a future placement
Source code
"use client";
type CarLoaderSize = "sm" | "md" | "lg";
interface CarLoaderProps {
accentColor?: string;
size?: CarLoaderSize;
label?: string;
className?: string;
}
const SIZE_DIMENSIONS: Record<CarLoaderSize, { width: number; height: number }> = {
sm: { width: 100, height: 50 },
md: { width: 140, height: 70 },
lg: { width: 180, height: 90 },
};
export function CarLoader({
accentColor = "#3f3cf2",
size = "md",
label = "Loading",
className,
}: CarLoaderProps) {
const { width, height } = SIZE_DIMENSIONS[size];
return (
<div
role="status"
aria-label={label}
className={["car-loader", className].filter(Boolean).join(" ")}
style={{ width, height, ["--car-accent" as string]: accentColor }}
>
<svg viewBox="0 0 200 100" fill="none">
<line
x1="0"
y1="92"
x2="200"
y2="92"
stroke="currentColor"
strokeOpacity="0.25"
strokeWidth="3"
strokeDasharray="10 8"
className="car-loader-road"
/>
<g className="car-loader-drive">
<path d="M15 78 L15 60 L38 60 L52 40 L128 40 L145 60 L170 60 L170 78 Z" fill="var(--car-accent)" />
<path d="M60 56 L70 44 L120 44 L134 56 Z" fill="white" fillOpacity="0.85" />
<rect x="14" y="70" width="10" height="6" rx="1" fill="var(--car-accent)" />
<g className="car-loader-wheel" style={{ transformOrigin: "48px 80px" }}>
<circle cx="48" cy="80" r="13" fill="#1f2937" />
<circle cx="48" cy="80" r="5" fill="var(--car-accent)" />
</g>
<g className="car-loader-wheel" style={{ transformOrigin: "150px 80px" }}>
<circle cx="150" cy="80" r="13" fill="#1f2937" />
<circle cx="150" cy="80" r="5" fill="var(--car-accent)" />
</g>
</g>
</svg>
<style jsx>{`
.car-loader {
display: inline-block;
color: var(--car-accent);
}
.car-loader svg {
width: 100%;
height: 100%;
overflow: hidden;
-webkit-mask-image: linear-gradient(to right, transparent 0%, black 14%, black 86%, transparent 100%);
mask-image: linear-gradient(to right, transparent 0%, black 14%, black 86%, transparent 100%);
}
.car-loader-drive {
animation: car-loader-drive 2.4s linear infinite;
}
.car-loader-wheel {
animation: car-loader-spin 0.8s linear infinite;
}
.car-loader-road {
animation: car-loader-road 0.9s linear infinite;
}
@keyframes car-loader-drive {
0% {
transform: translateX(-45px);
}
100% {
transform: translateX(220px);
}
}
@keyframes car-loader-spin {
to {
transform: rotate(360deg);
}
}
@keyframes car-loader-road {
to {
stroke-dashoffset: -18px;
}
}
@media (prefers-reduced-motion: reduce) {
.car-loader-drive,
.car-loader-wheel,
.car-loader-road {
animation-duration: 3s;
}
}
`}</style>
</div>
);
}
Usage
Import the component and use it like this.
import { CarLoader } from "./CarLoader";
export default function Example() {
return <CarLoader accentColor="#3f3cf2" size="md" label="Loading" />;
}
Dependencies
No external dependencies.
Usage notes
Pass an accentColor hex, size (sm/md/lg), and an optional label for the accessible status announcement.