Spinner
Apto para servidorAn indeterminate loading indicator.
Vista previa en vivo
Renderizado desde el código fuente instalado de VEXA — los mismos archivos que recibes.
Escritorio
LoadingLoadingLoading
Instalación
Añade el código del componente a tu proyecto. Las dependencias del registry se resuelven automáticamente.
npx shadcn@latest add https://vexa.valfiguer.com/r/spinner.jsonSe instala en components/vexa/spinner.tsx
Dependencias npm
Sin dependencias npm externas.
Dependencias del registry
- @vexa/utils
Otros items de VEXA que necesita este componente. Instálalos primero — la CLI los resuelve automáticamente.
Código
Cópialo a su ruta destino, o instálalo con el comando de arriba.
components/vexa/spinner.tsx
import type * as React from "react";
import { cn } from "@/lib/utils";
export interface SpinnerProps extends React.ComponentProps<"svg"> {
/**
* Accessible loading text announced via a visually-hidden `status` region.
* Provide a translated string; defaults to `"Loading"`.
*/
label?: string;
}
/**
* Spinner — an indeterminate loading indicator.
*
* RSC-safe. Exposes a `role="status"` live region with a visually-hidden label
* so screen readers announce the loading state. The rotation is disabled under
* reduced-motion while the accessible status text remains.
*/
export function Spinner({
className,
label = "Loading",
...props
}: SpinnerProps) {
return (
<span role="status" className="inline-flex items-center">
<svg
data-slot="spinner"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
className={cn(
"size-4 animate-spin text-current motion-reduce:animate-none",
className,
)}
{...props}
>
<circle
cx="12"
cy="12"
r="9"
stroke="currentColor"
strokeOpacity="0.25"
strokeWidth="2.5"
/>
<path
d="M21 12a9 9 0 0 0-9-9"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
/>
</svg>
<span className="sr-only">{label}</span>
</span>
);
}
JSON del registryr/spinner.json
r/spinner.json
{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "spinner",
"type": "registry:ui",
"title": "Spinner",
"description": "An indeterminate loading indicator.",
"registryDependencies": [
"@vexa/utils"
],
"files": [
{
"path": "registry/default/ui/spinner.tsx",
"type": "registry:ui",
"target": "components/vexa/spinner.tsx",
"content": "import type * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nexport interface SpinnerProps extends React.ComponentProps<\"svg\"> {\n /**\n * Accessible loading text announced via a visually-hidden `status` region.\n * Provide a translated string; defaults to `\"Loading\"`.\n */\n label?: string;\n}\n\n/**\n * Spinner — an indeterminate loading indicator.\n *\n * RSC-safe. Exposes a `role=\"status\"` live region with a visually-hidden label\n * so screen readers announce the loading state. The rotation is disabled under\n * reduced-motion while the accessible status text remains.\n */\nexport function Spinner({\n className,\n label = \"Loading\",\n ...props\n}: SpinnerProps) {\n return (\n <span role=\"status\" className=\"inline-flex items-center\">\n <svg\n data-slot=\"spinner\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n className={cn(\n \"size-4 animate-spin text-current motion-reduce:animate-none\",\n className,\n )}\n {...props}\n >\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"9\"\n stroke=\"currentColor\"\n strokeOpacity=\"0.25\"\n strokeWidth=\"2.5\"\n />\n <path\n d=\"M21 12a9 9 0 0 0-9-9\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n <span className=\"sr-only\">{label}</span>\n </span>\n );\n}\n"
}
],
"meta": {
"frameworks": [
"react",
"next"
],
"rsc": "server-safe",
"cssVars": [],
"a11y": "role=status live region with a visually-hidden label; rotation disabled under reduced motion.",
"example": "<Spinner label=\"Saving\" className=\"text-vexa-focus\" />",
"tests": "planned — see docs/README.md#roadmap"
}
}Detalles
Accesibilidad
role=status live region with a visually-hidden label; rotation disabled under reduced motion.