Dialog

A terminal-inspired dialog with square geometry and clear keyboard focus.

Confirm changes

Save your changes to this workspace.

"use client";
import { Dialog } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { useState } from "react";
export function Demo() {
  const [open, setOpen] = useState(false);
  return (
    <>
      <Button onClick={() => setOpen(true)}>Open dialog</Button>
      <Dialog open={open} onOpenChange={setOpen} title="Confirm changes">
        <p className="mb-6">Save your changes to this workspace.</p>
        <Button variant="secondary" onClick={() => setOpen(false)}>
          Save changes
        </Button>
      </Dialog>
    </>
  );
}

Installation

pnpm dlx shadcn@latest add https://ascii-cn.kdawg.dev/r/dialog.json

Usage

import { Dialog } from "@/components/ui/dialog"
components/ui/dialog.tsx
"use client";
import { useEffect, useRef, type ReactNode } from "react";
export function Dialog({
  open,
  onOpenChange,
  title,
  children,
}: {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  title: string;
  children: ReactNode;
}) {
  const ref = useRef<HTMLDialogElement>(null);
  useEffect(() => {
    const dialog = ref.current;
    if (open && !dialog?.open) dialog?.showModal();
    else if (!open && dialog?.open) dialog.close();
  }, [open]);
  return (
    <dialog
      ref={ref}
      aria-label={title}
      onCancel={() => onOpenChange(false)}
      onClose={() => onOpenChange(false)}
      className="fixed inset-0 m-auto max-h-[90dvh] w-[min(640px,calc(100%_-_32px))] overflow-auto border border-[#ffd15b] bg-black p-6 font-mono text-[#e8e8e5] backdrop:bg-black/80"
    >
      <div className="mb-6 flex items-center justify-between gap-4">
        <h2 className="text-[#ffd15b]">{title}</h2>
        <button
          type="button"
          aria-label="Close dialog"
          onClick={() => onOpenChange(false)}
          className="size-11 text-[#929da7] focus-visible:outline-2"
        >
          [x]
        </button>
      </div>
      {children}
    </dialog>
  );
}

Styling

Edit the component's Tailwind classes directly. Blue marks interactive controls; yellow highlights attention or a build action. Keep visible text labels alongside color.