Kosmesis
Components

Alert Dialog

A confirmation dialog for destructive/important actions, wrapping Morphos's AlertDialog primitive.

Installation

npx kosmesis add alert-dialog
pnpm dlx kosmesis add alert-dialog
yarn dlx kosmesis add alert-dialog
bunx kosmesis add alert-dialog

Install the following dependencies:

npm install @morphos/overlays
pnpm add @morphos/overlays
yarn add @morphos/overlays
bun add @morphos/overlays

This component builds on other Kosmesis components — install these first (via kosmesis add or this same manual process on their own pages): button.

Copy and paste the following code into your project.

alert-dialog.tsx
import { StatelessComponent } from "@praxisjs/core";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import {  AlertDialogAction as MorphosAlertDialogAction,  AlertDialogCancel as MorphosAlertDialogCancel,  AlertDialogContent as MorphosAlertDialogContent,  AlertDialogDescription as MorphosAlertDialogDescription,  AlertDialogTitle as MorphosAlertDialogTitle,  type AlertDialogActionProps as MorphosAlertDialogActionProps,  type AlertDialogCancelProps as MorphosAlertDialogCancelProps,  type AlertDialogContentProps as MorphosAlertDialogContentProps,  type AlertDialogDescriptionProps as MorphosAlertDialogDescriptionProps,  type AlertDialogTitleProps as MorphosAlertDialogTitleProps} from "@morphos/overlays";import { buttonVariants } from "./button";import { cn } from "@/lib/utils";/** * `AlertDialog` and `AlertDialogTrigger` are re-exported directly — see the note in `dialog.tsx` * for why: `new AlertDialog()` must produce a real instance with `.isOpen`/`.openDialog()`, which * a wrapping component class would not have. */export {  AlertDialog,  AlertDialogTrigger,  type AlertDialogProps,  type AlertDialogTriggerProps,} from "@morphos/overlays";export type AlertDialogContentProps = MorphosAlertDialogContentProps;@Component()export class AlertDialogContent extends StatelessComponent<AlertDialogContentProps> {  render() {    const { class: cls, ...rest } = this.props;    return (      <MorphosAlertDialogContent        class={cn(          "fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-lg border bg-background p-6 shadow-lg outline-none sm:max-w-lg",          "data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95",          cls,        )}        {...rest}      />    );  }}export interface AlertDialogSlotProps {  class?: string;  children?: Children;}@Component()export class AlertDialogHeader extends StatelessComponent<AlertDialogSlotProps> {  render() {    const { class: cls, children } = this.props;    return <div class={cn("flex flex-col gap-2 text-center sm:text-left", cls)}>{children}</div>;  }}@Component()export class AlertDialogFooter extends StatelessComponent<AlertDialogSlotProps> {  render() {    const { class: cls, children } = this.props;    return (      <div class={cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", cls)}>{children}</div>    );  }}export type AlertDialogTitleProps = MorphosAlertDialogTitleProps;@Component()export class AlertDialogTitle extends StatelessComponent<AlertDialogTitleProps> {  render() {    const { class: cls, ...rest } = this.props;    return <MorphosAlertDialogTitle class={cn("text-lg font-semibold", cls)} {...rest} />;  }}export type AlertDialogDescriptionProps = MorphosAlertDialogDescriptionProps;@Component()export class AlertDialogDescription extends StatelessComponent<AlertDialogDescriptionProps> {  render() {    const { class: cls, ...rest } = this.props;    return <MorphosAlertDialogDescription class={cn("text-sm text-muted-foreground", cls)} {...rest} />;  }}export type AlertDialogActionProps = MorphosAlertDialogActionProps;@Component()export class AlertDialogAction extends StatelessComponent<AlertDialogActionProps> {  render() {    const { class: cls, ...rest } = this.props;    return <MorphosAlertDialogAction class={cn(buttonVariants(), cls)} {...rest} />;  }}export type AlertDialogCancelProps = MorphosAlertDialogCancelProps;@Component()export class AlertDialogCancel extends StatelessComponent<AlertDialogCancelProps> {  render() {    const { class: cls, ...rest } = this.props;    return <MorphosAlertDialogCancel class={cn(buttonVariants({ variant: "outline" }), cls)} {...rest} />;  }}

Install the following dependencies:

npm install @morphos/overlays @praxisjs/css
pnpm add @morphos/overlays @praxisjs/css
yarn add @morphos/overlays @praxisjs/css
bun add @morphos/overlays @praxisjs/css

This component builds on other Kosmesis components — install these first (via kosmesis add or this same manual process on their own pages): button.

Copy and paste the following code into your project.

alert-dialog.tsx
import { StatelessComponent } from "@praxisjs/core";import { cx, keyframes, Stylesheet, Styled, tokenVars } from "@praxisjs/css";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import {  AlertDialogAction as MorphosAlertDialogAction,  AlertDialogCancel as MorphosAlertDialogCancel,  AlertDialogContent as MorphosAlertDialogContent,  AlertDialogDescription as MorphosAlertDialogDescription,  AlertDialogTitle as MorphosAlertDialogTitle,  type AlertDialogActionProps as MorphosAlertDialogActionProps,  type AlertDialogCancelProps as MorphosAlertDialogCancelProps,  type AlertDialogContentProps as MorphosAlertDialogContentProps,  type AlertDialogDescriptionProps as MorphosAlertDialogDescriptionProps,  type AlertDialogTitleProps as MorphosAlertDialogTitleProps} from "@morphos/overlays";import { ButtonStyles } from "./button";import { KosmesisTokens } from "@/lib/kosmesis-theme";const t = tokenVars(KosmesisTokens);const popIn = keyframes("kosmesis-pop-in", {  from: { opacity: "0", transform: "translate(-50%, -50%) scale(0.95)" },  to: { opacity: "1", transform: "translate(-50%, -50%) scale(1)" },});class AlertDialogStyles extends Stylesheet {  $content = this.css({    position: "fixed",    top: "50%",    left: "50%",    zIndex: 50,    display: "grid",    width: "100%",    maxWidth: "calc(100% - 2rem)",    transform: "translate(-50%, -50%)",    gap: "1rem",    borderRadius: "0.5rem",    border: `1px solid ${t.border}`,    backgroundColor: t.background,    padding: "1.5rem",    boxShadow: "0 10px 15px -3px rgb(0 0 0 / 0.1)",    outline: "none",  })    .media("(min-width: 640px)", { maxWidth: "32rem" })    .on("&[data-open]", { animation: `${popIn} 150ms ease-out` });  $header = this.css({ display: "flex", flexDirection: "column", gap: "0.5rem", textAlign: "center" }).media(    "(min-width: 640px)",    { textAlign: "left" },  );  $footer = this.css({ display: "flex", flexDirection: "column-reverse", gap: "0.5rem" }).media("(min-width: 640px)", {    flexDirection: "row",    justifyContent: "flex-end",  });  $title = this.css({ fontSize: "1.125rem", fontWeight: 600 });  $description = this.css({ fontSize: "0.875rem", color: t.mutedForeground });}/** * `AlertDialog` and `AlertDialogTrigger` are re-exported directly — see the note in `dialog.tsx` * for why: `new AlertDialog()` must produce a real instance with `.isOpen`/`.openDialog()`, which * a wrapping component class would not have. */export { AlertDialog, AlertDialogTrigger, type AlertDialogProps, type AlertDialogTriggerProps } from "@morphos/overlays";export type AlertDialogContentProps = MorphosAlertDialogContentProps;@Component()export class AlertDialogContent extends StatelessComponent<AlertDialogContentProps> {  @Styled(AlertDialogStyles) $s!: AlertDialogStyles;  render() {    const { class: cls, ...rest } = this.props;    return <MorphosAlertDialogContent class={cx(this.$s.$content, cls)} {...rest} />;  }}export interface AlertDialogSlotProps {  class?: string;  children?: Children;}@Component()export class AlertDialogHeader extends StatelessComponent<AlertDialogSlotProps> {  @Styled(AlertDialogStyles) $s!: AlertDialogStyles;  render() {    const { class: cls, children } = this.props;    return <div class={cx(this.$s.$header, cls)}>{children}</div>;  }}@Component()export class AlertDialogFooter extends StatelessComponent<AlertDialogSlotProps> {  @Styled(AlertDialogStyles) $s!: AlertDialogStyles;  render() {    const { class: cls, children } = this.props;    return <div class={cx(this.$s.$footer, cls)}>{children}</div>;  }}export type AlertDialogTitleProps = MorphosAlertDialogTitleProps;@Component()export class AlertDialogTitle extends StatelessComponent<AlertDialogTitleProps> {  @Styled(AlertDialogStyles) $s!: AlertDialogStyles;  render() {    const { class: cls, ...rest } = this.props;    return <MorphosAlertDialogTitle class={cx(this.$s.$title, cls)} {...rest} />;  }}export type AlertDialogDescriptionProps = MorphosAlertDialogDescriptionProps;@Component()export class AlertDialogDescription extends StatelessComponent<AlertDialogDescriptionProps> {  @Styled(AlertDialogStyles) $s!: AlertDialogStyles;  render() {    const { class: cls, ...rest } = this.props;    return <MorphosAlertDialogDescription class={cx(this.$s.$description, cls)} {...rest} />;  }}export type AlertDialogActionProps = MorphosAlertDialogActionProps;@Component()export class AlertDialogAction extends StatelessComponent<AlertDialogActionProps> {  @Styled(ButtonStyles) $btn!: ButtonStyles;  render() {    const { class: cls, ...rest } = this.props;    return <MorphosAlertDialogAction class={cx(this.$btn.$root, this.$btn.$variantDefault, this.$btn.$sizeDefault, cls)} {...rest} />;  }}export type AlertDialogCancelProps = MorphosAlertDialogCancelProps;@Component()export class AlertDialogCancel extends StatelessComponent<AlertDialogCancelProps> {  @Styled(ButtonStyles) $btn!: ButtonStyles;  render() {    const { class: cls, ...rest } = this.props;    return <MorphosAlertDialogCancel class={cx(this.$btn.$root, this.$btn.$variantOutline, this.$btn.$sizeDefault, cls)} {...rest} />;  }}

Examples

Usage

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

@Component()
class DeleteAccountDialog extends StatefulComponent {
  @State() alertDialog = new AlertDialog();

  render() {
    return (
      <>
        <AlertDialogTrigger alertDialog={this.alertDialog} class={buttonVariants({ variant: "destructive" })}>
          Delete account
        </AlertDialogTrigger>
        <AlertDialogContent alertDialog={this.alertDialog} aria-labelledby="delete-title">
          <AlertDialogHeader>
            <AlertDialogTitle id="delete-title">Are you absolutely sure?</AlertDialogTitle>
            <AlertDialogDescription>
              This action cannot be undone. This will permanently delete your account.
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel alertDialog={this.alertDialog}>Cancel</AlertDialogCancel>
            <AlertDialogAction alertDialog={this.alertDialog}>Continue</AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </>
    );
  }
}

Unlike Dialog, AlertDialogContent has no close (✕) button and no closeOnOutsideClick by default — the user must explicitly choose Cancel or Continue.

Props

AlertDialog

Re-exported directly from @morphos/overlays — instantiate it in state (@State() alertDialog = new AlertDialog()) and pass it to every part below.

PropTypeDefault
openboolean— controlled open state
defaultOpenboolean
onOpenChange(open: boolean) => void
closeOnEscapeboolean
closeOnOutsideClickboolean

AlertDialogTrigger

PropTypeDefault
alertDialogAlertDialog— required

AlertDialogContent

PropTypeDefault
alertDialogAlertDialog— required
aria-labelstring
aria-labelledbystring
aria-describedbystring

AlertDialogTitle

PropTypeDefault
as"h1" | "h2" | "h3" | "h4" | "h5" | "h6"

AlertDialogAction / AlertDialogCancel

PropTypeDefault
alertDialogAlertDialog— required
onClick() => void

AlertDialogDescription, AlertDialogHeader, and AlertDialogFooter take no props beyond class/children.

On this page