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 =...