Skip to content
Gx
GitHub

Alert Dialog

A modal that asks for a decision.

<alertdialog.AlertDialog id="demo-alert" title="Delete this item?" description="This action cannot be undone.">
  <:confirm><button.Button variant={button.Destructive}>Delete</button.Button></:confirm>
  <:trigger><button.Button variant={button.Outline}>Delete</button.Button></:trigger>
</alertdialog.AlertDialog>

Installation

Run the command in the app module.

Terminal
gx add alert-dialog

The command also installs button.

The command writes these files.

File Path in the app
AlertDialog.gx ui/alert-dialog/AlertDialog.gx
AlertDialog.fixtures.go ui/alert-dialog/AlertDialog.fixtures.go
styles.go ui/alert-dialog/styles.go

Install button first.

Copy each file to its path in the app. Change each import of a registry package to the path of that package in the app.

ui/alert-dialog/AlertDialog.gx
package alertdialog

import "github.com/alternayte/gx/registry/button"

props {
  // Id is the id of the dialog element.
  // The trigger points at it, so it must be unique on the page.
  Id          string
  // Title is the heading of the alert dialog. It states the question.
  Title       string
  // Description is the text below the title. An empty value renders no description.
  Description string = ""
  // Size sets the maximum width and the layout: Md or Sm.
  // Sm centres the text and puts the buttons side by side.
  Size        Size = Md
  // Media is an icon or image shown in a tile next to the title. A nil value renders no tile.
  Media       gx.Node = nil
  // Trigger is the control that opens the alert dialog.
  Trigger     gx.Node = nil
  // Confirm is the control that confirms the action. It renders after the cancel button.
  Confirm     gx.Node = nil
  // Cancel is the label of the cancel button, which closes the alert dialog.
  // An empty value is Cancel.
  Cancel      string = "Cancel"
  // Open renders the alert dialog open. The default is closed.
  Open        bool = false
  // Class adds classes to the dialog element.
  Class       string = ""
  // Children is the content of the alert dialog body, between the header and the buttons.
  Children    gx.Node = nil
  // Attrs adds HTML attributes to the dialog element.
  Attrs       gx.Attrs = nil
}

<span class="contents">
  if p.Trigger != nil {
    <span data-gx-open={"#" + p.Id} class="contents">{p.Trigger}</span>
  }
  <dialog id={p.Id} open={p.Open} role="alertdialog" data-gx-dismiss="manual" data-gx-trap data-size={p.size()} class={gx.Cx("group/alert-dialog-content fixed inset-0 m-auto h-fit w-full max-w-[calc(100%-2rem)] gap-4 rounded-lg border border-border bg-background p-6 text-foreground shadow-lg outline-none open:grid data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-lg opacity-0 scale-95 transition-[opacity,scale,overlay,display] transition-discrete duration-200 open:opacity-100 open:scale-100 starting:open:opacity-0 starting:open:scale-95 motion-reduce:transition-none backdrop:bg-black/50 backdrop:opacity-0 backdrop:transition-[opacity,overlay,display] backdrop:transition-discrete backdrop:duration-200 open:backdrop:opacity-100 starting:open:backdrop:opacity-0 motion-reduce:backdrop:transition-none", p.Class)} {...p.Attrs}>
    <div class="grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-6 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]">
      if p.Media != nil {
        <div data-slot="alert-dialog-media" class="mb-2 inline-flex size-16 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-8">{p.Media}</div>
      }
      <h2 class="text-lg font-semibold sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2">{p.Title}</h2>
      if p.Description != "" {
        <p class="text-sm text-muted-foreground">{p.Description}</p>
      }
    </div>
    if p.Children != nil {
      <div class="text-sm">{p.Children}</div>
    }
    <div class="flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end">
      <button.Button variant={button.Outline} attrs={gx.Attrs{gx.Bool("data-gx-close", true)}}>{p.cancel()}</button.Button>
      if p.Confirm != nil {
        {p.Confirm}
      }
    </div>
  </dialog>
</span>
ui/alert-dialog/AlertDialog.fixtures.go
package alertdialog

import (
	"github.com/alternayte/gx"
	"github.com/alternayte/gx/registry/button"
)

var AlertDialogFixtures = gx.Fixtures[AlertDialogProps]{
	"Default": {
		Id:          "demo-alert",
		Title:       "Delete this item?",
		Description: "This action cannot be undone.",
		Confirm:     button.Button(button.ButtonProps{Variant: button.Destructive, Children: gx.Text("Delete")}),
		Trigger:     button.Button(button.ButtonProps{Variant: button.Outline, Children: gx.Text("Delete")}),
	},
}
ui/alert-dialog/styles.go
package alertdialog

// Size is the width of an alert dialog.
type Size string

// The sizes of alertdialog.AlertDialog.
const (
	Md Size = "default"
	Sm Size = "sm"
)

// size returns the data-size value; a zero value is Md.
func (p AlertDialogProps) size() string {
	if p.Size == "" {
		return string(Md)
	}
	return string(p.Size)
}

// cancel returns the label of the cancel button; a zero value is Cancel.
func (p AlertDialogProps) cancel() string {
	if p.Cancel == "" {
		return "Cancel"
	}
	return p.Cancel
}

The theme must define these tokens: --background, --foreground, --border, --muted, --muted-foreground, --ring.

Usage

<alertdialog.AlertDialog id="delete" title="Delete this item?" description="This action cannot be undone."
  confirm={button.Button(button.ButtonProps{Variant: button.Destructive, Children: gx.Text("Delete")})}>
  <:trigger><button.Button variant={button.Outline}>Delete</button.Button></:trigger>
</alertdialog.AlertDialog>

Examples

Default

<alertdialog.AlertDialog id="demo-alert" title="Delete this item?" description="This action cannot be undone.">
  <:confirm><button.Button variant={button.Destructive}>Delete</button.Button></:confirm>
  <:trigger><button.Button variant={button.Outline}>Delete</button.Button></:trigger>
</alertdialog.AlertDialog>

API reference

A tag sets a prop by its name with a lower-case first letter: Class is class.

alertdialog.AlertDialog

Prop Type Default Description
Id string Required Id is the id of the dialog element. The trigger points at it, so it must be unique on the page.
Title string Required Title is the heading of the alert dialog. It states the question.
Description string "" Description is the text below the title. An empty value renders no description.
Size Size Md Size sets the maximum width and the layout: Md or Sm. Sm centres the text and puts the buttons side by side.
Media gx.Node nil Media is an icon or image shown in a tile next to the title. A nil value renders no tile.
Trigger gx.Node nil Trigger is the control that opens the alert dialog.
Confirm gx.Node nil Confirm is the control that confirms the action. It renders after the cancel button.
Cancel string "Cancel" Cancel is the label of the cancel button, which closes the alert dialog. An empty value is Cancel.
Open bool false Open renders the alert dialog open. The default is closed.
Class string "" Class adds classes to the dialog element.
Children gx.Node nil Children is the content of the alert dialog body, between the header and the buttons.
Attrs gx.Attrs nil Attrs adds HTML attributes to the dialog element.

Do and do not

Do

  • Follow the question with the two outcomes.
  • Name the confirm button after the action.

Don't

  • Do not close an alert dialog on an outside click.
  • Do not use an alert dialog for a message with one outcome. Use a dialog.

Keyboard

Key Action
Enter, Space Opens the alert dialog from the trigger.
Tab Cycles through Cancel and Confirm.
Escape Does not close the alert dialog.