Create a dialog box with input fields and buttons

by Vasil Svetoslavov

HTML

<dialog id="d1" backdrop="true">
  <h3 class="dialog-title drag-handle">Greetings, one and all!</h3>
  <form method="dialog">
    <fieldset>
      <legend>Fill your details</legend>
      <label for="fname">First Name</label>
      <input type="text" id="fname" /><br />
      <label for="lname">Last Name</label>
      <input type="text" id="lname" />
    </fieldset>
    <div class="toolbar">
      <button onclick="autoFill();">Auto-Fill</button>
      <button id="btnOK" onclick="ok();">OK</button>
    </div>
  </form>

</dialog>
<button onclick="showDialog();">Ask me</button>

<script>

  // Optional: later, detach.destroy() to remove listeners
</script>

CSS

dialog button {
  background-color: #ccc;
  border: 1px solid #999;
  border-radius: 4px;
  height: 2rem;
  padding: 6px;
}
dialog button:hover {
  background-color: #ddd;
}
#btnOK {
  float: right;
  background-color: #696;
  border-color: #363;
  color: #fff;
}
#btnOK:hover {
  background-color: #363;
}

dialog {
  margin: 20px;
  border: 1px solid #999;
  padding: 0px 10px;
  line-height: 2.3rem;
  box-shadow: 2px 2px 5px 0 #333;
  overflow-x: hidden;
  width: 300px;
  min-width: 300px;
  max-width: 300px;
  border-radius: 5px;
}
.drag-handle {
  cursor: move;
  user-select: none;
  touch-action: none; /* enables smooth PointerEvents on touch */
}

dialog::backdrop {
  /*
  background: #3F5EFB;
background: radial-gradient(circle, rgba(63, 94, 251, .5) 0%, rgba(252, 70, 107, .3) 100%);
*/
background: #59C173;  /* fallback for old browsers */
/*
background: -webkit-linear-gradient(to top left, #5D26C1, #a17fe0, #59C173);
background: linear-gradient(to top left, #5D26C1, #a17fe0, #59C173);
*/
background: linear-gradient(-45deg, #5D26C1, #a17fe0, #59C173, #5D26C1);
  
opacity: 0.7;
  background-size: 600% 600%;
  animation: gradientShift 1ms ease-in-out infinite;

}

@keyframes gradientShift {
  0% {
    background-position: 0% 50%;
  }
  25% {
    background-position: 50% 100%;
  }
  50% {
    background-position: 100% 50%;
  }
  75% {
    background-position: 50% 0%;
  }
  100% {
    background-position: 0% 50%;
  }
}
dialog .dialog-title {
  position: relative;
  display: block;
  width: 100%;
  left: -10px;
  margin-top: 0;
  padding-left: 10px;
  padding-right: 10px;
  background-color: #eee;
  border-bottom: 1px solid #999;
}

dialog .toolbar {
  padding: 5px;
  border-top: 1px solid #999;
  background-color: #ccc;
  display: block;
  position: relative;
  left: -10px;
  width: calc(100% + 10px);
}

dialog fieldset {
  border: none;
  border-top: 1px solid green;
}

JavaScript

function dialog() {
  return document.getElementById('d1');
}

function dialogTitle() {
  const _d = dialog();
  const _dt = _d.querySelector('.dialog-title');
  return _dt;
}

function fname() {
  return document.getElementById('fname');
}

function lname() {
  return document.getElementById('lname');
}

function showDialog() {
  dialog().showModal();
}

function autoFill() {
  fname().value = 'Jack';
  lname().value = 'Daniels';
}

function ok() {
  fname().value = '';
  lname().value = '';
  dialog().close();
}

// DRAG'N'DROP

// Make an existing <dialog> draggable via a handle element.
// Usage: makeDialogDraggable(document.querySelector('#myDialog'), document.querySelector('#myHandle'));
function makeDialogDraggable(dlg, handle, opts = {}) {
  if (!dlg) console.log('No dialog!');
  if (!handle) console.log('No handle!');
  if (!dlg || !handle) return;
  const options = { clampToViewport: true, edgeMargin: 20, ...opts };

  let dragging = false;
  let startPointer = { x: 0, y: 0 };
  let startPos = { left: 0, top: 0 };

  function ensureFixedPosition() {
    // Keep impact minimal: only enforce fixed positioning while dragging
    const cs = getComputedStyle(dlg);
    if (cs.position !== 'fixed') dlg.style.position = 'fixed';
    // UA may center <dialog> via margins; zero them so left/top are literal
    if (cs.margin !== '0px') dlg.style.margin = '0';
    // Remove any centering transform so left/top stick
    dlg.style.transform = 'none';
  }

  function clamp(val, min, max) {
    return Math.min(Math.max(val, min), max);
  }

  function positionDialog(left, top) {
    if (!options.clampToViewport) {
      dlg.style.left = left + 'px';
      dlg.style.top = top + 'px';
      return;
    }
    const rect = dlg.getBoundingClientRect();
    const vw = window.innerWidth;
    const vh = window.innerHeight;

    // Keep some of the dialog visible at all times
    const minLeft =...