Viana Kitv0.1.4

Components

Alert Dialog

A modal dialog that interrupts the user with important content and expects a response. Use it for irreversible or high-consequence actions.

example.tsx

Import

tsx
import {
  AppAlertDialog,
  AppAlertDialogTrigger,
  AppAlertDialogContent,
  AppAlertDialogHeader,
  AppAlertDialogTitle,
  AppAlertDialogDescription,
  AppAlertDialogFooter,
  AppAlertDialogAction,
  AppAlertDialogCancel,
} from "@/components/primitives/AppAlertDialog"

Anatomy

The Alert Dialog is composed of several parts that work together. Every usage must include a trigger, content, a title, and at least one action.

tsx
<AppAlertDialog>
  <AppAlertDialogTrigger asChild>
    <AppButton>Open</AppButton>
  </AppAlertDialogTrigger>
  <AppAlertDialogContent>
    <AppAlertDialogHeader>
      <AppAlertDialogTitle>Title</AppAlertDialogTitle>
      <AppAlertDialogDescription>Description</AppAlertDialogDescription>
    </AppAlertDialogHeader>
    <AppAlertDialogFooter>
      <AppAlertDialogCancel>Cancel</AppAlertDialogCancel>
      <AppAlertDialogAction>Confirm</AppAlertDialogAction>
    </AppAlertDialogFooter>
  </AppAlertDialogContent>
</AppAlertDialog>

Variants

Both AppAlertDialogAction and AppAlertDialogCancel accept a variant prop to control their color. Use destructive on the action for irreversible operations.

Destructive action

example.tsx

Secondary action

example.tsx
tsx
// Available variants for AppAlertDialogAction and AppAlertDialogCancel
"default"     // bg-primary — use for standard confirmations
"destructive" // bg-destructive — use for delete / irreversible actions
"secondary"   // bg-secondary — use for lower-emphasis confirmations
"outline"     // transparent with border — use for cancel / dismiss

Trigger

Pass asChild on AppAlertDialogTrigger to use any element as the trigger — typically an AppButton. Without asChild, the trigger renders as a plain <button>.

tsx
{/* Recommended — use AppButton as trigger */}
<AppAlertDialogTrigger asChild>
  <AppButton variant="destructive">Delete</AppButton>
</AppAlertDialogTrigger>

Controlled

Use open and onOpenChange to control the dialog from outside — for example, to open it programmatically without a trigger element.

tsx
const [open, setOpen] = useState(false)

<AppAlertDialog open={open} onOpenChange={setOpen}>
  <AppAlertDialogContent>
    {/* ... */}
  </AppAlertDialogContent>
</AppAlertDialog>

API Reference

AppAlertDialog and its sub-components extend their underlying Radix UI primitives.

PropTypeDefaultDescription
openbooleanControlled open state of the dialog.
defaultOpenbooleanfalseInitial open state when uncontrolled.
onOpenChange(open: boolean) => voidCallback fired when the open state changes.
asChildbooleanfalseOn AppAlertDialogTrigger — merges props onto the child element instead of rendering a <button>.
variant"default" | "destructive" | "secondary" | "outline""default"On AppAlertDialogAction and AppAlertDialogCancel — controls the button color using semantic design tokens.
AppAlertDialogTitle defaults to text-2xl. AppAlertDialogDescription defaults to text-base. Both overridable via className.
classNamestringAdditional Tailwind classes merged via cn(). Applied after variant classes, so it always wins.

Source

src/components/primitives/AppAlertDialog.tsx
import * as React from "react"
import {
  AlertDialog,
  AlertDialogPortal,
  AlertDialogOverlay,
  AlertDialogTrigger,
  AlertDialogContent,
  AlertDialogHeader,
  AlertDialogFooter,
  AlertDialogTitle,
  AlertDialogDescription,
  AlertDialogAction,
  AlertDialogCancel,
} from "@/components/ui/alert-dialog"
import { cn } from "@/lib/utils"

const actionVariantClasses = {
  default: "bg-primary text-primary-foreground hover:bg-primary/90",
  destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
  outline: "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
} as const

const cancelVariantClasses = {
  default: "bg-primary text-primary-foreground hover:bg-primary/90",
  destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
  outline: "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
} as const

type ActionVariant = keyof typeof actionVariantClasses

type AppAlertDialogActionProps = React.ComponentPropsWithoutRef<typeof AlertDialogAction> & {
  variant?: ActionVariant
}

const AppAlertDialog = AlertDialog
const AppAlertDialogPortal = AlertDialogPortal
const AppAlertDialogOverlay = AlertDialogOverlay
const AppAlertDialogTrigger = AlertDialogTrigger
const AppAlertDialogContent = AlertDialogContent
const AppAlertDialogHeader = AlertDialogHeader
const AppAlertDialogFooter = AlertDialogFooter

const AppAlertDialogTitle = React.forwardRef<
  React.ComponentRef<typeof AlertDialogTitle>,
  React.ComponentPropsWithoutRef<typeof AlertDialogTitle>
>(({ className, ...props }, ref) => (
  <AlertDialogTitle ref={ref} className={cn("text-2xl", className)} {...props} />
))
AppAlertDialogTitle.displayName = "AppAlertDialogTitle"

const AppAlertDialogDescription = React.forwardRef<
  React.ComponentRef<typeof AlertDialogDescription>,
  React.ComponentPropsWithoutRef<typeof AlertDialogDescription>
>(({ className, ...props }, ref) => (
  <AlertDialogDescription ref={ref} className={cn("text-base", className)} {...props} />
))
AppAlertDialogDescription.displayName = "AppAlertDialogDescription"

const AppAlertDialogAction = React.forwardRef<
  React.ComponentRef<typeof AlertDialogAction>,
  AppAlertDialogActionProps
>(({ className, variant = "default", ...props }, ref) => (
  <AlertDialogAction
    ref={ref}
    className={cn(actionVariantClasses[variant], className)}
    {...props}
  />
))
AppAlertDialogAction.displayName = "AppAlertDialogAction"

const AppAlertDialogCancel = React.forwardRef<
  React.ComponentRef<typeof AlertDialogCancel>,
  AppAlertDialogActionProps
>(({ className, variant = "default", ...props }, ref) => (
  <AlertDialogCancel
    ref={ref}
    className={cn(cancelVariantClasses[variant], className)}
    {...props}
  />
))
AppAlertDialogCancel.displayName = "AppAlertDialogCancel"

export {
  AppAlertDialog,
  AppAlertDialogPortal,
  AppAlertDialogOverlay,
  AppAlertDialogTrigger,
  AppAlertDialogContent,
  AppAlertDialogHeader,
  AppAlertDialogFooter,
  AppAlertDialogTitle,
  AppAlertDialogDescription,
  AppAlertDialogAction,
  AppAlertDialogCancel,
}
export type { AppAlertDialogActionProps, ActionVariant }