Meowland docs
Workbench

Component reference

DialogPanel

The body of a dialog, with an optional header that stays in place while the body scrolls.

Preview

Fixed header and body scrolling

Short forms keep their natural height; long bodies and host-constrained windows share the same page shell. Forms still use native submit and cancel.

packages/meowtail/stories/dialog-layout.stories.tsxline 30tsx
render() {
  return (
    <Specimen
      label="Open a dialog"
      note="Each dialog keeps its title and close action fixed while the body scrolls."
    >
      <Inline gap="compact">
        {(["short", "long", "limited", "workspace"] as const).map((kind) => {
          let dialog: HTMLDialogElement | undefined;
          const name = {
            short: "Short form",
            long: "Long body",
            limited: "Limited height",
            workspace: "Full workspace",
          }[kind];
          return (
            <div>
              <Button
                variant="outline"
                size={kind === "limited" ? "small" : "default"}
                onClick={() => {
                  dialog?.showModal();
                }}
              >
                Open {name}
              </Button>
              <Dialog
                labelledBy={`${kind}-title`}
                style={
                  kind === "limited"
                    ? { maxHeight: "40svh" }
                    : kind === "workspace"
                      ? { height: "100dvh", maxHeight: "none" }
                      : undefined
                }
                ref={(element: HTMLDialogElement) => {
                  dialog = element;
                }}
              >
                <DialogPanel
                  as="form"
                  method="dialog"
                  header={
                    <DialogHeader
                      title={`${name} · Current item and close action`}
                      titleId={`${kind}-title`}
                      actions={
                        <IconButton
                          label={`Close ${name}`}
                          onClick={() => {
                            dialog?.close("cancel");
                          }}
                        >
                          <Icon name="x" />
                        </IconButton>
                      }
                    />
                  }
                >
                  <Stack gap="compact">
                    <Field label={`${name} draft`} htmlFor={`${kind}-draft`}>
                      <Input
                        id={`${kind}-draft`}
                        name="draft"
                        value="Keep the current input"
                        required
                      />
                    </Field>
                    {kind !== "short" ? (
                      Array.from({ length: 24 }, (_, i) => (
                        <p>
                          Body {i + 1}: Reading content, editing the draft, and closing the window
                          stay independent; the title and close entry always belong to the same
                          top region.
                        </p>
                      ))
                    ) : (
                      <p>A short form uses only the height its content needs.</p>
                    )}
                  </Stack>
                  <Button
                    type="submit"
                    value="save"
                    size={kind === "limited" ? "small" : "default"}
                  >
                    Save {name}
                  </Button>
                </DialogPanel>
              </Dialog>
            </div>
          );
        })}
      </Inline>
    </Specimen>
  );
}

Installation

bun add meowtail

Usage

usage.tsts
import { DialogPanel } from "meowtail";

API reference

Props

PropTypeDefault
as
"div" | "form""div"
header
Child–

Also takes className, children and the attributes and events of its root element.

DOM parts

root

Registry

The component is registered as dialog-panel in the meowtail component registry.