Skip to main content
astrocraft-ui/ components · 101

Alert Dialog

Free · MIT

Headless, accessible, and styled entirely through the attribute surface below — bring your own CSS system, or start from the reference theme.

Install

Without a flag you get no styling at all — plain HTML carrying the attribute surface below. --theme copies the same theme in two dialects;--bridge lumos re-points either one onto Lumos for Astro's tokens (it needs a theme to re-point, and Lumos itself, already in your project).

Unstyled — behavior only, you write the CSS

Install command
npx astrocraft-ui add overlays/alert-dialog

Plain-CSS theme — no build step

Install command
npx astrocraft-ui add overlays/alert-dialog --theme css

Tailwind theme — needs Tailwind v4

Install command
npx astrocraft-ui add overlays/alert-dialog --theme tailwind

Plain-CSS theme, re-pointed onto Lumos tokens

Install command
npx astrocraft-ui add overlays/alert-dialog --theme css --bridge lumos

Tailwind theme, re-pointed onto Lumos tokens

Install command
npx astrocraft-ui add overlays/alert-dialog --theme tailwind --bridge lumos

Live demo

AlertDialog

Click the backdrop: nothing happens, which is the whole difference from Dialog. Escape still cancels, and focus lands on Keep it rather than on the destructive button — so the key you reach for to make an interruption go away does not delete anything.

Delete “Orbit” and its 34 files?

This removes the project for everyone on the team. It cannot be undone.

Attribute surface

With no class-merging machinery, these attributes are the whole extension point. State is a data-attribute or a native attribute; visibility is the hiddenattribute. Generated from source by pnpm slots.

ComponentSlotsVariantsRuntime stateNative state
`AlertDialog.astro``alert-dialog`———
`AlertDialogAction.astro``alert-dialog-action``data-variant`: `primary` · `secondary` · `outline` · `ghost` · `destructive`
`data-size`: `sm` · `md` · `lg`
——
`AlertDialogCancel.astro``alert-dialog-cancel``data-variant`: `primary` · `secondary` · `outline` · `ghost` · `destructive`
`data-size`: `sm` · `md` · `lg`
——
`AlertDialogDescription.astro``alert-dialog-description`———
`AlertDialogTitle.astro``alert-dialog-title`———

Source

What the command copies — 6 files, alias-free so the copy lands standing alone. This is the whole component, shown without its comments; the files you install keep them, with the reasoning behind every rule.

src/components/ui/overlays/alert-dialog/AlertDialog.astro
---
import "../../_overlay.css";

import type { HTMLAttributes } from "astro/types";

type Props = HTMLAttributes<"dialog">;

const { class: className, ...rest } = Astro.props;
---

<dialog role="alertdialog" class={className} data-slot="alert-dialog" {...rest}>
  <slot />
</dialog>

<script>
  import "../../_dialog";

  import { onReadyOnce } from "../../_once";

  function wire(root: HTMLElement) {
    root.addEventListener(
      "click",
      (event) => {
        if (event.target === root) event.stopPropagation();
      },
      true,
    );
  }

  onReadyOnce('[data-slot="alert-dialog"]', wire);
</script>
src/components/ui/overlays/alert-dialog/AlertDialogAction.astro
---
import type { HTMLAttributes } from "astro/types";

type Props = HTMLAttributes<"button"> & {
  variant?: "primary" | "secondary" | "outline" | "ghost" | "destructive";
  size?: "sm" | "md" | "lg";
};

const { variant = "primary", size = "md", class: className, ...rest } = Astro.props;
---

<button
  type="button"
  data-dialog-close
  data-slot="alert-dialog-action"
  data-variant={variant}
  data-size={size}
  class={className}
  {...rest}
>
  <slot />
</button>
src/components/ui/overlays/alert-dialog/AlertDialogCancel.astro
---
import type { HTMLAttributes } from "astro/types";

type Props = HTMLAttributes<"button"> & {
  variant?: "primary" | "secondary" | "outline" | "ghost" | "destructive";
  size?: "sm" | "md" | "lg";
};

const {
  variant = "outline",
  size = "md",
  autofocus = true,
  class: className,
  ...rest
} = Astro.props;
---

{}
<button
  type="button"
  autofocus={autofocus}
  data-dialog-close
  data-slot="alert-dialog-cancel"
  data-variant={variant}
  data-size={size}
  class={className}
  {...rest}
>
  <slot />
</button>
src/components/ui/overlays/alert-dialog/AlertDialogDescription.astro
---
import type { HTMLAttributes } from "astro/types";

type Props = HTMLAttributes<"p">;

const { class: className, ...rest } = Astro.props;
---

<p class={className} data-slot="alert-dialog-description" {...rest}><slot /></p>
src/components/ui/overlays/alert-dialog/AlertDialogTitle.astro
---
import type { HTMLAttributes } from "astro/types";

type Props = HTMLAttributes<"h2">;

const { class: className, ...rest } = Astro.props;
---

<h2 class={className} data-slot="alert-dialog-title" {...rest}><slot /></h2>
src/components/ui/overlays/alert-dialog/index.ts
import { DialogTrigger as AlertDialogTrigger } from "../../overlays/dialog";
import AlertDialog from "./AlertDialog.astro";
import AlertDialogAction from "./AlertDialogAction.astro";
import AlertDialogCancel from "./AlertDialogCancel.astro";
import AlertDialogDescription from "./AlertDialogDescription.astro";
import AlertDialogTitle from "./AlertDialogTitle.astro";

export {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogDescription,
  AlertDialogTitle,
  AlertDialogTrigger,
};
export default AlertDialog;

What you get

The component source, copied into your project by npx astrocraft-ui add overlays/alert-dialog — no package dependency, no CSS to fight. Whatever the paid blocks compose, this is it.