HextaUI

Alert dialog

Yıkıcı ya da önemli eylemler için, asenkron işin bitmesini bekleyen ve telefonlarda alt sayfaya dönüşen bir onay iletişim kutusu.

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
import { Button } from "@/components/ui/button"

export function AlertDialogDemo() {
  return (
    <AlertDialog>
      <AlertDialogTrigger render={<Button variant="outline" />}>
        Show dialog
      </AlertDialogTrigger>
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle>Publish changes?</AlertDialogTitle>
          <AlertDialogDescription>
            Your changes will be visible to everyone with the link.
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Cancel</AlertDialogCancel>
          <AlertDialogAction>Publish</AlertDialogAction>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/alert-dialog.json

Bileşeni, HextaUI tema token'larını ve bileşenin bağımlı olduğu tüm HextaUI bileşenlerini ekler.

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
<AlertDialog>
  <AlertDialogTrigger render={<Button variant="outline" />}>
    Delete
  </AlertDialogTrigger>
  <AlertDialogContent>
    <AlertDialogHeader>
      <AlertDialogTitle>Delete this project?</AlertDialogTitle>
      <AlertDialogDescription>This can’t be undone.</AlertDialogDescription>
    </AlertDialogHeader>
    <AlertDialogFooter>
      <AlertDialogCancel>Cancel</AlertDialogCancel>
      <AlertDialogAction>Delete</AlertDialogAction>
    </AlertDialogFooter>
  </AlertDialogContent>
</AlertDialog>
AlertDialog
├── AlertDialogTrigger
└── AlertDialogContent
    ├── AlertDialogHeader
    │   ├── AlertDialogMedia
    │   ├── AlertDialogTitle
    │   └── AlertDialogDescription
    └── AlertDialogFooter
        ├── AlertDialogCancel
        └── AlertDialogAction

Asenkron eylem

<AlertDialogAction /> bileşeninin onClick'inden bir promise döndürün. Düğme bir spinner gösterir ve promise sonuçlanana kadar diyalog kapatılamaz. Promise çözülünce kapanır, reddedilince açık kalır; böylece kişi yeniden deneyebilir.

"use client"

import * as React from "react"
import { IconTrash } from "@tabler/icons-react"

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogMedia,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
import { Button } from "@/components/ui/button"

function wait(ms: number) {
  return new Promise((resolve) => setTimeout(resolve, ms))
}

export function AlertDialogAsyncAction() {
  const [shouldFail, setShouldFail] = React.useState(false)
  const [attempts, setAttempts] = React.useState(0)

  return (
    <div className="flex flex-wrap items-center gap-2">
      <AlertDialog onOpenChange={(open) => open && setAttempts(0)}>
        <AlertDialogTrigger render={<Button variant="destructive" />}>
          Delete project
        </AlertDialogTrigger>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogMedia variant="destructive">
              <IconTrash />
            </AlertDialogMedia>
            <AlertDialogTitle>Delete “Acme website”?</AlertDialogTitle>
            <AlertDialogDescription>
              {attempts > 0
                ? `Deleting failed ${attempts} time${attempts > 1 ? "s" : ""}. Try again.`
                : "All deployments, domains and environment variables will be removed. This can’t be undone."}
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>Cancel</AlertDialogCancel>
            <AlertDialogAction
              variant="destructive"
              onClick={async () => {
                await wait(1500)
                if (shouldFail) {
                  setAttempts((count) => count + 1)
                  throw new Error("Request failed")
                }
              }}
            >
              Delete project
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
      <Button
        variant="ghost"
        size="sm"
        aria-pressed={shouldFail}
        onClick={() => setShouldFail(!shouldFail)}
      >
        Request will {shouldFail ? "fail" : "succeed"}
      </Button>
    </div>
  )
}

Media

<AlertDialogMedia /> bir simgeyi masaüstünde başlığın yanına, telefonlarda üstüne yerleştirir. Yıkıcı eylemler için variant="destructive" kullanın.

import { IconTrash } from "@tabler/icons-react"

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogMedia,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
import { Button } from "@/components/ui/button"

export function AlertDialogWithMedia() {
  return (
    <AlertDialog>
      <AlertDialogTrigger render={<Button variant="outline" />}>
        Delete file
      </AlertDialogTrigger>
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogMedia variant="destructive">
            <IconTrash />
          </AlertDialogMedia>
          <AlertDialogTitle>Delete “invoice-2026.pdf”?</AlertDialogTitle>
          <AlertDialogDescription>
            The file moves to the trash and is removed after 30 days.
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Cancel</AlertDialogCancel>
          <AlertDialogAction variant="destructive">Delete</AlertDialogAction>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  )
}

Küçük

size="sm" içeriği ortalar ve düğmeleri yan yana dizer; kısa sorular için uygundur.

import { IconLogout } from "@tabler/icons-react"

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogMedia,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
import { Button } from "@/components/ui/button"

export function AlertDialogSmall() {
  return (
    <AlertDialog>
      <AlertDialogTrigger render={<Button variant="outline" />}>
        Sign out
      </AlertDialogTrigger>
      <AlertDialogContent size="sm">
        <AlertDialogHeader>
          <AlertDialogMedia>
            <IconLogout />
          </AlertDialogMedia>
          <AlertDialogTitle>Sign out?</AlertDialogTitle>
          <AlertDialogDescription>
            You’ll need to sign in again on this device.
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Cancel</AlertDialogCancel>
          <AlertDialogAction>Sign out</AlertDialogAction>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  )
}

Ayrık tetikleyiciler

Tek bir diyaloğu birçok trigger arasında paylaşmak için createAlertDialogHandle() ile bir handle oluşturun. Her trigger kendi payload'ını geçirir ve diyalog bunu bir render fonksiyonu aracılığıyla okur.

"use client"

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
  createAlertDialogHandle,
} from "@/components/ui/alert-dialog"
import { Button } from "@/components/ui/button"

const removeMember = createAlertDialogHandle<{ name: string }>()

export function AlertDialogDetachedTriggers() {
  return (
    <div className="flex flex-wrap gap-2">
      {["Olivia", "Liam"].map((name) => (
        <AlertDialogTrigger
          key={name}
          handle={removeMember}
          payload={{ name }}
          render={<Button variant="outline" />}
        >
          Remove {name}
        </AlertDialogTrigger>
      ))}
      <AlertDialog handle={removeMember}>
        {({ payload }) => (
          <AlertDialogContent size="sm">
            <AlertDialogHeader>
              <AlertDialogTitle>Remove {payload?.name}?</AlertDialogTitle>
              <AlertDialogDescription>
                They’ll lose access to this workspace.
              </AlertDialogDescription>
            </AlertDialogHeader>
            <AlertDialogFooter>
              <AlertDialogCancel>Cancel</AlertDialogCancel>
              <AlertDialogAction variant="destructive">
                Remove
              </AlertDialogAction>
            </AlertDialogFooter>
          </AlertDialogContent>
        )}
      </AlertDialog>
    </div>
  )
}

Kontrollü

Trigger olmadan koddan açmak için open ve onOpenChange geçin. Odak yine Cancel üzerine iner.

"use client"

import * as React from "react"

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from "@/components/ui/alert-dialog"
import { Button } from "@/components/ui/button"

export function AlertDialogControlled() {
  const [open, setOpen] = React.useState(false)

  return (
    <>
      <Button
        variant="outline"
        onClick={() => window.setTimeout(() => setOpen(true), 600)}
      >
        Open in 600ms
      </Button>
      <AlertDialog open={open} onOpenChange={setOpen}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>Session expiring</AlertDialogTitle>
            <AlertDialogDescription>
              You’ve been inactive for a while. Stay signed in?
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>Sign out</AlertDialogCancel>
            <AlertDialogAction>Stay signed in</AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </>
  )
}

İç içe

Başka bir diyaloğun içinden açılan diyalog üste yığılır. Alt diyalog, üsttekiyle birlikte küçülür ve üsttekiyle birlikte kapandığında yeniden öne gelir.

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
import { Button } from "@/components/ui/button"

export function AlertDialogNested() {
  return (
    <AlertDialog>
      <AlertDialogTrigger render={<Button variant="outline" />}>
        Reset settings
      </AlertDialogTrigger>
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle>Reset all settings?</AlertDialogTitle>
          <AlertDialogDescription>
            Theme, notifications and shortcuts go back to their defaults.
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Cancel</AlertDialogCancel>
          <AlertDialog>
            <AlertDialogTrigger render={<Button variant="destructive" />}>
              Reset
            </AlertDialogTrigger>
            <AlertDialogContent size="sm">
              <AlertDialogHeader>
                <AlertDialogTitle>Are you really sure?</AlertDialogTitle>
                <AlertDialogDescription>
                  The parent dialog steps back while this one is open.
                </AlertDialogDescription>
              </AlertDialogHeader>
              <AlertDialogFooter>
                <AlertDialogCancel>Go back</AlertDialogCancel>
                <AlertDialogAction variant="destructive">
                  Reset
                </AlertDialogAction>
              </AlertDialogFooter>
            </AlertDialogContent>
          </AlertDialog>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  )
}

Uzun içerik

Ekrandan uzun içerik, sayfa kilitli kalırken diyaloğun içinde kayar.

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
import { Button } from "@/components/ui/button"

const sections = Array.from({ length: 12 }, (_, index) => index + 1)

export function AlertDialogLongContent() {
  return (
    <AlertDialog>
      <AlertDialogTrigger render={<Button variant="outline" />}>
        Review terms
      </AlertDialogTrigger>
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle>Accept the updated terms?</AlertDialogTitle>
          <AlertDialogDescription render={<div />}>
            {sections.map((section) => (
              <p key={section}>
                Section {section}. We may update these terms from time to time.
                Continued use of the service after changes take effect means you
                accept the new terms. Read the <a href="#">full policy</a> for
                details.
              </p>
            ))}
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Decline</AlertDialogCancel>
          <AlertDialogAction>Accept</AlertDialogAction>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  )
}

Sağdan sola

İçeriğe de dir geçin; çünkü içerik, RTL kapsayıcınızın dışındaki bir portal içinde oluşturulur. Alt bölümdeki ok tuşları okuma yönünü izler.

import { IconTrash } from "@tabler/icons-react"

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogMedia,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
import { Button } from "@/components/ui/button"

export function AlertDialogRtl() {
  return (
    <div dir="rtl">
      <AlertDialog>
        <AlertDialogTrigger render={<Button variant="outline" />}>
          حذف الملف
        </AlertDialogTrigger>
        <AlertDialogContent dir="rtl">
          <AlertDialogHeader>
            <AlertDialogMedia variant="destructive">
              <IconTrash />
            </AlertDialogMedia>
            <AlertDialogTitle>حذف هذا الملف؟</AlertDialogTitle>
            <AlertDialogDescription>
              لا يمكن التراجع عن هذا الإجراء.
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>إلغاء</AlertDialogCancel>
            <AlertDialogAction variant="destructive">حذف</AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </div>
  )
}
TuşAction
EnterSpaceTrigger üzerinde, diyaloğu açar ve odağı Cancel'a taşır.
TabShift+TabOdağı kontroller arasında taşır. Odak içeride kalır.
←→↑↓Alt bölümdeki düğmeler arasında gezinir ve başa sarar. Sol ve sağ, okuma yönünü izler.
EscDiyaloğu kapatır ve odağı trigger'a geri verir. Asenkron bir eylem çalışırken yok sayılır.
  • İçerikte role="alertdialog" bulunur; başlığıyla etiketlenir ve açıklamasıyla tanımlanır.
  • Odak, en az yıkıcı seçenek olan <AlertDialogCancel /> üzerinde başlar. Değiştirmek için initialFocus geçin.
  • Arka plana tıklamak diyaloğu kapatmaz; böylece bir karar yanlışlıkla geçilmez. İzin vermek için disablePointerDismissal={false} ayarlayın.
  • Telefonlarda, iptal etmek için aşağı kaydırılabilen bir alt sheet'e dönüşür. Bir eylem beklemedeyken kaydırma, Esc ve Cancel engellenir; düğmeler odaklanabilir kalır.
  • Azaltılmış hareket açıkken ölçeklenmek yerine solarak görünür.

<Sheet /> aracılığıyla Base UI drawer üzerine kuruludur. Her parça, sardığı primitive veya öğenin prop'larını kabul eder.

PropTürVarsayılan
open
boolean–
defaultOpen
booleanfalse
onOpenChangeBeklemedeki bir eylem tarafından engellenen kapatmalarda çağrılmaz.
(open: boolean, details) => void–
onOpenChangeCompleteAçma ya da kapatma animasyonundan sonra çağrılır.
(open: boolean) => void–
disablePointerDismissalArka plan tıklamalarında diyaloğu açık tutar.
booleantrue
handleAyrık tetikleyicileri bağlar.
AlertDialogHandle<Payload>–
actionsRefDiyaloğu kod üzerinden kapatın veya kaldırın.
RefObject<{ close, unmount }>–
children
ReactNode | ({ payload }) => ReactNode–
PropTürVarsayılan
handle
AlertDialogHandle<Payload>–
payloadDiyaloğun render fonksiyonuna geçirilir.
Payload–
render
ReactElement | (props, state) => ReactElement<button>
ÖznitelikAçıklama
data-slot="alert-dialog-trigger"CSS'te tetikleyicileri hedefleyin.
data-popup-openDiyaloğu açıkken bulunur.
PropTürVarsayılan
size
"default" | "sm""default"
initialFocus
boolean | RefObject | (openType) => HTMLElement | booleanCancel button
finalFocus
boolean | RefObject | (closeType) => HTMLElement | booleanThe trigger
dirDiyalog sağdan sola olacaksa ayarlayın.
"ltr" | "rtl"–
render
ReactElement | (props, state) => ReactElement<div>
ÖznitelikAçıklama
data-slot="alert-dialog-content"CSS'te diyaloğu hedefleyin.
data-sizeGeçerli boyut.
data-openAçıkken bulunur.
data-starting-styleDiyalog açılma animasyonu sırasında bulunur.
data-ending-styleDiyalog kapanma animasyonu sırasında bulunur.
data-nested-drawer-openÜstte iç içe bir diyalog açıkken bulunur.
data-swipingTelefonda kaydırılırken bulunur.
--nested-drawersBunun üstünde kaç diyalog açık.

Medyayı, başlığı ve açıklamayı üst üste dizen bir <div>.

ÖznitelikAçıklama
data-slot="alert-dialog-header"CSS'te başlığı hedefleyin.
PropTürVarsayılan
variant
"default" | "destructive""default"
ÖznitelikAçıklama
data-slot="alert-dialog-media"CSS'te medyayı hedefleyin.
PropTürVarsayılan
render
ReactElement | (props, state) => ReactElement<h2>
ÖznitelikAçıklama
data-slot="alert-dialog-title"CSS'te başlığı hedefleyin.
PropTürVarsayılan
renderBirden çok paragraf içerdiğinde render={<div />} kullanın.
ReactElement | (props, state) => ReactElement<p>
ÖznitelikAçıklama
data-slot="alert-dialog-description"CSS'te açıklamayı hedefleyin.

Düğmeler için bir <div>. Düğmeler telefonlarda tam genişlikte üst üste dizilir ve ok tuşları aralarında geçiş yapar.

ÖznitelikAçıklama
data-slot="alert-dialog-footer"CSS'te alt bölümü hedefleyin.

Tıklandığında diyaloğu kapatan bir <Button />. Button'ın tüm prop'larını kabul eder.

PropTürVarsayılan
onClickBir spinner göstermek ve sonuçlanana kadar diyaloğu açık tutmak için bir promise döndürün. Açık tutmak için event.preventDefault() çağırın.
(event) => void | PromiseLike<unknown>–
variant
ButtonVariant"default"
ÖznitelikAçıklama
data-slot="alert-dialog-action"CSS'te eylemleri hedefleyin.
PropTürVarsayılan
variant
ButtonVariant"outline"
size
ButtonSize–
disabledBir eylem beklemedeyken de devre dışıdır.
boolean–
ÖznitelikAçıklama
data-slot="alert-dialog-cancel"CSS'te iptal düğmesini hedefleyin. İlk odağı o alır.
data-disabledDevre dışıyken bulunur.

<AlertDialogContent /> ikisini de zaten oluşturur. Bunları yalnızca özel bir popup oluştururken kullanın.

PropTürVarsayılan
keepMountedPortal üzerinde, diyaloğu kapalıyken de DOM'da tutar.
booleanfalse

Sayfanın herhangi bir yerindeki <AlertDialogTrigger /> öğelerini tek bir <AlertDialog /> ile bağlayan bir handle döndürür. Payload'u bir generic ile tiplendirin: createAlertDialogHandle<{ name: string }>().

Kullanıldığı bloklar

Alert dialog üzerine kurulan bloklar.