AlertDialog
Hoja clienteA 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.jsonSe instala en components/vexa/alert-dialog.tsx
Dependencias npm
- @radix-ui/react-alert-dialog
Dependencias del registry
- @vexa/utils
- @vexa/button
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.