Saltar al contenido
VEXA
Navegación y menús

Tabs

Hoja cliente

Switch between related panels.

Vista previa en vivo

Renderizado desde el código fuente instalado de VEXA — los mismos archivos que recibes.

Escritorio
A summary of your workspace and recent usage.

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/tabs.json

Se instala en components/vexa/tabs.tsx

Dependencias npm

  • @radix-ui/react-tabs

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/tabs.tsx
"use client";

import type * as React from "react";
import * as TabsPrimitive from "@radix-ui/react-tabs";

import { cn } from "@/lib/utils";

/**
 * Tabs — switch between related panels.
 *
 * Client leaf. Radix implements the APG tabs pattern: roving `Tab`/`Shift+Tab`
 * focus onto the active trigger, Arrow keys to move between triggers (Home/End
 * to jump), and `tab`/`tabpanel` roles with `aria-selected`/`aria-controls`
 * wired up. Automatic activation is the default; set `activationMode="manual"`
 * for panels whose content is expensive to render.
 */
export function Tabs({
  className,
  ...props
}: React.ComponentProps<typeof TabsPrimitive.Root>) {
  return (
    <TabsPrimitive.Root
      data-slot="tabs"
      className={cn("flex flex-col gap-3", className)}
      {...props}
    />
  );
}

export function TabsList({
  className,
  ...props
}: React.ComponentProps<typeof TabsPrimitive.List>) {
  return (
    <TabsPrimitive.List
      data-slot="tabs-list"
      className={cn(
        "inline-flex h-10 w-fit items-center justify-center gap-1 rounded-vexa-md bg-vexa-muted p-1 text-vexa-muted-foreground",
        className,
      )}
      {...props}
    />
  );
}

export function TabsTrigger({
  className,
  ...props
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
  return (
    <TabsPrimitive.Trigger
      data-slot="tabs-trigger"
      className={cn(
        "inline-flex items-center justify-center gap-1.5 whitespace-nowrap rounded-vexa-sm px-3 py-1.5 text-sm font-medium",
        "transition-[color,background-color,box-shadow] duration-[var(--vexa-duration-fast)] ease-[var(--vexa-ease-standard)]",
        "outline-none focus-visible:ring-2 focus-visible:ring-vexa-ring focus-visible:ring-offset-2 focus-visible:ring-offset-vexa-background",
        "disabled:pointer-events-none disabled:opacity-50",
        "data-[state=active]:bg-vexa-surface-raised data-[state=active]:text-vexa-foreground data-[state=active]:shadow-vexa-sm",
        "[&_svg]:size-4 [&_svg]:shrink-0",
        className,
      )}
      {...props}
    />
  );
}

export function TabsContent({
  className,
  ...props
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
  return (
    <TabsPrimitive.Content
      data-slot="tabs-content"
      className={cn(
        "outline-none focus-visible:ring-2 focus-visible:ring-vexa-ring focus-visible:ring-offset-2 focus-visible:ring-offset-vexa-background",
        className,
      )}
      {...props}
    />
  );
}
JSON del registryr/tabs.json
r/tabs.json
{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tabs",
  "type": "registry:ui",
  "title": "Tabs",
  "description": "Switch between related panels.",
  "dependencies": [
    "@radix-ui/react-tabs"
  ],
  "registryDependencies": [
    "@vexa/utils"
  ],
  "files": [
    {
      "path": "registry/default/ui/tabs.tsx",
      "type": "registry:ui",
      "target": "components/vexa/tabs.tsx",
      "content": "\"use client\";\n\nimport type * as React from \"react\";\nimport * as TabsPrimitive from \"@radix-ui/react-tabs\";\n\nimport { cn } from \"@/lib/utils\";\n\n/**\n * Tabs — switch between related panels.\n *\n * Client leaf. Radix implements the APG tabs pattern: roving `Tab`/`Shift+Tab`\n * focus onto the active trigger, Arrow keys to move between triggers (Home/End\n * to jump), and `tab`/`tabpanel` roles with `aria-selected`/`aria-controls`\n * wired up. Automatic activation is the default; set `activationMode=\"manual\"`\n * for panels whose content is expensive to render.\n */\nexport function Tabs({\n  className,\n  ...props\n}: React.ComponentProps<typeof TabsPrimitive.Root>) {\n  return (\n    <TabsPrimitive.Root\n      data-slot=\"tabs\"\n      className={cn(\"flex flex-col gap-3\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function TabsList({\n  className,\n  ...props\n}: React.ComponentProps<typeof TabsPrimitive.List>) {\n  return (\n    <TabsPrimitive.List\n      data-slot=\"tabs-list\"\n      className={cn(\n        \"inline-flex h-10 w-fit items-center justify-center gap-1 rounded-vexa-md bg-vexa-muted p-1 text-vexa-muted-foreground\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport function TabsTrigger({\n  className,\n  ...props\n}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {\n  return (\n    <TabsPrimitive.Trigger\n      data-slot=\"tabs-trigger\"\n      className={cn(\n        \"inline-flex items-center justify-center gap-1.5 whitespace-nowrap rounded-vexa-sm px-3 py-1.5 text-sm font-medium\",\n        \"transition-[color,background-color,box-shadow] duration-[var(--vexa-duration-fast)] ease-[var(--vexa-ease-standard)]\",\n        \"outline-none focus-visible:ring-2 focus-visible:ring-vexa-ring focus-visible:ring-offset-2 focus-visible:ring-offset-vexa-background\",\n        \"disabled:pointer-events-none disabled:opacity-50\",\n        \"data-[state=active]:bg-vexa-surface-raised data-[state=active]:text-vexa-foreground data-[state=active]:shadow-vexa-sm\",\n        \"[&_svg]:size-4 [&_svg]:shrink-0\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport function TabsContent({\n  className,\n  ...props\n}: React.ComponentProps<typeof TabsPrimitive.Content>) {\n  return (\n    <TabsPrimitive.Content\n      data-slot=\"tabs-content\"\n      className={cn(\n        \"outline-none focus-visible:ring-2 focus-visible:ring-vexa-ring focus-visible:ring-offset-2 focus-visible:ring-offset-vexa-background\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n"
    }
  ],
  "meta": {
    "frameworks": [
      "react",
      "next"
    ],
    "rsc": "client",
    "exports": [
      "Tabs",
      "TabsList",
      "TabsTrigger",
      "TabsContent"
    ],
    "cssVars": [
      "--vexa-muted",
      "--vexa-muted-foreground",
      "--vexa-surface-raised",
      "--vexa-foreground",
      "--vexa-ring",
      "--vexa-background"
    ],
    "a11y": "APG tabs: roving Tab focus onto the active trigger, Arrow/Home/End to move between triggers, and tab/tabpanel roles with aria-selected/aria-controls.",
    "example": "<Tabs defaultValue=\"a\"><TabsList><TabsTrigger value=\"a\">Account</TabsTrigger></TabsList><TabsContent value=\"a\">...</TabsContent></Tabs>",
    "tests": "registry/tests/tabs.test.tsx"
  }
}

Detalles

Accesibilidad

APG tabs: roving Tab focus onto the active trigger, Arrow/Home/End to move between triggers, and tab/tabpanel roles with aria-selected/aria-controls.