Saltar al contenido
VEXA
Overlays

AlertDialog

Hoja cliente

A modal that interrupts to confirm a consequential action.

Vista previa en vivo

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

Escritorio

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/alert-dialog.json

Se instala en components/vexa/alert-dialog.tsx

Dependencias npm

  • @radix-ui/react-alert-dialog

Dependencias del registry

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

import type * as React from "react";
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";

import { cn } from "@/lib/utils";
import { buttonVariants } from "@/components/vexa/button";

/**
 * AlertDialog — a modal that interrupts to confirm a consequential or
 * destructive action.
 *
 * Client leaf. Unlike `Dialog`, it is `role="alertdialog"`, cannot be dismissed
 * by clicking the backdrop, and requires an explicit choice via
 * `AlertDialogAction` / `AlertDialogCancel`. Radix handles focus trapping,
 * Escape-to-cancel, and focus return (§14.2). Give it a title and a description
 * that names the consequence.
 */
export function AlertDialog(
  props: React.ComponentProps<typeof AlertDialogPrimitive.Root>,
) {
  return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
}

export function AlertDialogTrigger(
  props: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>,
) {
  return (
    <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
  );
}

export function AlertDialogPortal(
  props: React.ComponentProps<typeof AlertDialogPrimitive.Portal>,
) {
  return (
    <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
  );
}

export function AlertDialogOverlay({
  className,
  ...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
  return (
    <AlertDialogPrimitive.Overlay
      data-slot="alert-dialog-overlay"
      className={cn(
        "fixed inset-0 z-50 bg-vexa-background/70 backdrop-blur-sm",
        "transition-opacity duration-[var(--vexa-duration-base)] ease-[var(--vexa-ease-standard)] motion-reduce:transition-none",
        "data-[state=closed]:opacity-0 data-[state=open]:opacity-100",
        className,
      )}
      {...props}
    />
  );
}

export function AlertDialogContent({
  className,
  ...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Content>) {
  return (
    <AlertDialogPortal>
      <AlertDialogOverlay />
      <AlertDialogPrimitive.Content
        data-slot="alert-dialog-content"
        className={cn(
          "fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4",
          "rounded-vexa-lg border border-vexa-border bg-vexa-surface-raised p-6 text-vexa-foreground shadow-vexa-lg",
          "transition-[opacity,transform] duration-[var(--vexa-duration-base)] ease-[var(--vexa-ease-standard)] motion-reduce:transition-none",
          "data-[state=closed]:scale-95 data-[state=closed]:opacity-0 data-[state=open]:scale-100 data-[state=open]:opacity-100",
          "focus-visible:outline-none",
          className,
        )}
        {...props}
      />
    </AlertDialogPortal>
  );
}

export function AlertDialogHeader({
  className,
  ...props
}: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="alert-dialog-header"
      className={cn("flex flex-col gap-1.5 text-left", className)}
      {...props}
    />
  );
}

export function AlertDialogFooter({
  className,
  ...props
}: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="alert-dialog-footer"
      className={cn(
        "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
        className,
      )}
      {...props}
    />
  );
}

export function AlertDialogTitle({
  className,
  ...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
  return (
    <AlertDialogPrimitive.Title
      data-slot="alert-dialog-title"
      className={cn(
        "text-lg font-semibold leading-none tracking-tight",
        className,
      )}
      {...props}
    />
  );
}

export function AlertDialogDescription({
  className,
  ...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
  return (
    <AlertDialogPrimitive.Description
      data-slot="alert-dialog-description"
      className={cn("text-sm text-vexa-muted-foreground", className)}
      {...props}
    />
  );
}

export function AlertDialogAction({
  className,
  ...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Action>) {
  return (
    <AlertDialogPrimitive.Action
      data-slot="alert-dialog-action"
      className={cn(buttonVariants({ variant: "primary" }), className)}
      {...props}
    />
  );
}

export function AlertDialogCancel({
  className,
  ...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) {
  return (
    <AlertDialogPrimitive.Cancel
      data-slot="alert-dialog-cancel"
      className={cn(buttonVariants({ variant: "outline" }), className)}
      {...props}
    />
  );
}
JSON del registryr/alert-dialog.json
r/alert-dialog.json
{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "alert-dialog",
  "type": "registry:ui",
  "title": "AlertDialog",
  "description": "A modal that interrupts to confirm a consequential action.",
  "dependencies": [
    "@radix-ui/react-alert-dialog"
  ],
  "registryDependencies": [
    "@vexa/utils",
    "@vexa/button"
  ],
  "files": [
    {
      "path": "registry/default/ui/alert-dialog.tsx",
      "type": "registry:ui",
      "target": "components/vexa/alert-dialog.tsx",
      "content": "\"use client\";\n\nimport type * as React from \"react\";\nimport * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\n\nimport { cn } from \"@/lib/utils\";\nimport { buttonVariants } from \"@/components/vexa/button\";\n\n/**\n * AlertDialog — a modal that interrupts to confirm a consequential or\n * destructive action.\n *\n * Client leaf. Unlike `Dialog`, it is `role=\"alertdialog\"`, cannot be dismissed\n * by clicking the backdrop, and requires an explicit choice via\n * `AlertDialogAction` / `AlertDialogCancel`. Radix handles focus trapping,\n * Escape-to-cancel, and focus return (§14.2). Give it a title and a description\n * that names the consequence.\n */\nexport function AlertDialog(\n  props: React.ComponentProps<typeof AlertDialogPrimitive.Root>,\n) {\n  return <AlertDialogPrimitive.Root data-slot=\"alert-dialog\" {...props} />;\n}\n\nexport function AlertDialogTrigger(\n  props: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>,\n) {\n  return (\n    <AlertDialogPrimitive.Trigger data-slot=\"alert-dialog-trigger\" {...props} />\n  );\n}\n\nexport function AlertDialogPortal(\n  props: React.ComponentProps<typeof AlertDialogPrimitive.Portal>,\n) {\n  return (\n    <AlertDialogPrimitive.Portal data-slot=\"alert-dialog-portal\" {...props} />\n  );\n}\n\nexport function AlertDialogOverlay({\n  className,\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {\n  return (\n    <AlertDialogPrimitive.Overlay\n      data-slot=\"alert-dialog-overlay\"\n      className={cn(\n        \"fixed inset-0 z-50 bg-vexa-background/70 backdrop-blur-sm\",\n        \"transition-opacity duration-[var(--vexa-duration-base)] ease-[var(--vexa-ease-standard)] motion-reduce:transition-none\",\n        \"data-[state=closed]:opacity-0 data-[state=open]:opacity-100\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport function AlertDialogContent({\n  className,\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Content>) {\n  return (\n    <AlertDialogPortal>\n      <AlertDialogOverlay />\n      <AlertDialogPrimitive.Content\n        data-slot=\"alert-dialog-content\"\n        className={cn(\n          \"fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4\",\n          \"rounded-vexa-lg border border-vexa-border bg-vexa-surface-raised p-6 text-vexa-foreground shadow-vexa-lg\",\n          \"transition-[opacity,transform] duration-[var(--vexa-duration-base)] ease-[var(--vexa-ease-standard)] motion-reduce:transition-none\",\n          \"data-[state=closed]:scale-95 data-[state=closed]:opacity-0 data-[state=open]:scale-100 data-[state=open]:opacity-100\",\n          \"focus-visible:outline-none\",\n          className,\n        )}\n        {...props}\n      />\n    </AlertDialogPortal>\n  );\n}\n\nexport function AlertDialogHeader({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"alert-dialog-header\"\n      className={cn(\"flex flex-col gap-1.5 text-left\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function AlertDialogFooter({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"alert-dialog-footer\"\n      className={cn(\n        \"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport function AlertDialogTitle({\n  className,\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {\n  return (\n    <AlertDialogPrimitive.Title\n      data-slot=\"alert-dialog-title\"\n      className={cn(\n        \"text-lg font-semibold leading-none tracking-tight\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport function AlertDialogDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {\n  return (\n    <AlertDialogPrimitive.Description\n      data-slot=\"alert-dialog-description\"\n      className={cn(\"text-sm text-vexa-muted-foreground\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function AlertDialogAction({\n  className,\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Action>) {\n  return (\n    <AlertDialogPrimitive.Action\n      data-slot=\"alert-dialog-action\"\n      className={cn(buttonVariants({ variant: \"primary\" }), className)}\n      {...props}\n    />\n  );\n}\n\nexport function AlertDialogCancel({\n  className,\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) {\n  return (\n    <AlertDialogPrimitive.Cancel\n      data-slot=\"alert-dialog-cancel\"\n      className={cn(buttonVariants({ variant: \"outline\" }), className)}\n      {...props}\n    />\n  );\n}\n"
    }
  ],
  "meta": {
    "frameworks": [
      "react",
      "next"
    ],
    "rsc": "client",
    "exports": [
      "AlertDialog",
      "AlertDialogTrigger",
      "AlertDialogPortal",
      "AlertDialogOverlay",
      "AlertDialogContent",
      "AlertDialogHeader",
      "AlertDialogFooter",
      "AlertDialogTitle",
      "AlertDialogDescription",
      "AlertDialogAction",
      "AlertDialogCancel"
    ],
    "cssVars": [
      "--vexa-background",
      "--vexa-border",
      "--vexa-surface-raised",
      "--vexa-foreground",
      "--vexa-muted-foreground",
      "--vexa-primary",
      "--vexa-primary-foreground",
      "--vexa-input",
      "--vexa-ring"
    ],
    "a11y": "role=alertdialog; not dismissible by clicking the backdrop and requires an explicit Action/Cancel choice. Focus is trapped, Escape cancels, and focus returns to the trigger. Actions reuse buttonVariants.",
    "example": "<AlertDialog><AlertDialogTrigger asChild><Button variant=\"danger\">Delete</Button></AlertDialogTrigger><AlertDialogContent><AlertDialogHeader><AlertDialogTitle>Delete project?</AlertDialogTitle><AlertDialogDescription>This cannot be undone.</AlertDialogDescription></AlertDialogHeader><AlertDialogFooter><AlertDialogCancel>Cancel</AlertDialogCancel><AlertDialogAction>Delete</AlertDialogAction></AlertDialogFooter></AlertDialogContent></AlertDialog>",
    "tests": "planned — see docs/README.md#roadmap"
  }
}

Detalles

Accesibilidad

role=alertdialog; not dismissible by clicking the backdrop and requires an explicit Action/Cancel choice. Focus is trapped, Escape cancels, and focus returns to the trigger. Actions reuse buttonVariants.