Skip to content

Prompt / form

A form dialog shows the full data round-trip: show({ title, initial }) passes data in, and onConfirm({ name }) returns typed data out. The result is { name } | undefined.

import { useState } from "react";
import { createDialog, type DialogComponentProps } from "./dialog-fn";

type Input = { title: string; initial?: string };
type Output = { name: string };

function PromptDialog({ isOpen, data, onClose, onConfirm }: DialogComponentProps<Input, Output>) {
  return (
    <dialog open={isOpen}>
      <form
        className="panel"
        onSubmit={(e) => {
          e.preventDefault();
          const form = new FormData(e.currentTarget);
          onConfirm?.({ name: String(form.get("name") ?? "") });
        }}
      >
        <h3>{data?.title}</h3>
        <input name="name" defaultValue={data?.initial} placeholder="Your name" autoFocus />
        <div className="row">
          <button type="button" onClick={onClose}>
            Cancel
          </button>
          <button type="submit" className="primary">
            Save
          </button>
        </div>
      </form>
    </dialog>
  );
}

const { Dialog, show } = createDialog(PromptDialog);

export default function App() {
  const [name, setName] = useState("");

  async function edit() {
    // Data flows in (title/initial) and back out (the typed result).
    const result = await show({ title: "Edit your name", initial: name });
    if (result) setName(result.name);
  }

  return (
    <main>
      <p>
        Name: <strong>{name || "—"}</strong>
      </p>
      <button className="primary" onClick={edit}>
        Edit name
      </button>
      <Dialog />
    </main>
  );
}