Saltar al contenido
VEXA
Feedback

Spinner

Apto para servidor

An 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.json

Se 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.