'Why drag and dragstart event are still triggered when draggable attribute is set to false?

I have this sketch application, which allows user to draw some pictures by pressing and moving the mouse.

/* create grids in canvas */
const initCanvas = function() {
    const canvas = document.querySelector('.canvas');
    /* clear old canvas if any */
    canvas.innerHTML = '';
    /* create new canvas */
    let row = parseInt(document.querySelector('textarea.canvasRow').value);
    let column = parseInt(document.querySelector('textarea.canvasColumn').value);
    if (!row || !column) return;
    canvas.style['grid-template-columns'] = `repeat(${column}, 1fr)`;
    canvas.style['grid-template-rows'] = `repeat(${row}, 1fr)`;
    for (let i = 0; i < (row * column); i++) {
        let cell = document.createElement('div');
        cell.classList.add('cell');
        cell.draggable = false; // prevent cell from being dragged
        cell.addEventListener('mousedown', draw, false);
        cell.addEventListener('mouseenter', draw, false); // mouseenter is better than mouseover
        canvas.appendChild(cell);
    }
}

/* mousedown event handler on canvas */
const toDraw = function(e) {
    // e.preventDefault(); // !IMPORTANT: inhibit some browser's default drag & drop behaviors
    isDrawing = true;
}

/* mouseenter event handler on each cell */
const draw = function(e) {
    // e.preventDefault(); // !IMPORTANT: inhibit some browser's default drag & drop behaviors
    if (isDrawing) {
        this.style['background-color'] = color;
    }
}

/* mouseup event handler on whole document */
const stopDrawing = function(e) {
    isDrawing = false;
    e.stopPropagation();
}

/* variables */
let color = 'black';
let isDrawing = false;
/* canvas init */
const initCanvasBtn = document.querySelector('.initCanvas');
initCanvasBtn.addEventListener('click', initCanvas);
/* draw */
const canvas = document.querySelector('.canvas');
canvas.draggable = false; // prevent canvas from being dragged
canvas.addEventListener('mousedown', toDraw, true); // capture must be true. canvas must turn on "isDrawing" before cell capture the mousedown event.
document.addEventListener('mouseup', stopDrawing, true); // document element handle this. no need to notify children.
textarea.canvasRow,
textarea.canvasColumn {
    width: 4rem;
    height: 1rem;
}

.initCanvas {
    width: 4rem;
    height: 2rem;
    border: 1px solid black;
}

.canvas {
    height: 50vw;
    width: 50vw;
    border: 1px solid black;
    display: grid;
}

.cell {
    background-color: #F5F5F5;
    border: 1px solid #EBEBEB;
}
<textarea class="canvasRow">16</textarea>
<textarea class="canvasColumn">16</textarea>
<div class="initCanvas">Create canvas</div>
<div class="canvas"></div>

According to MDN Web Docs: draggable, to prevent element from being dragged, I set the draggable attribute of both canvas and cell to false.

cell.draggable = false;
canvas.draggable = false;

But when I test it, in 1/20 or 1/30 of cases, a no-drop cursor icon appears, and my mouseup event will be swollen. That means a drag operation occurred, which is not expected.

enter image description here

According to MDN Web Docs: HTML Drag and Drop API I bind a listener on dragstart and drag event. Then debugger's Event Listener Breakpoint showed that both drag and dragstart events were fired when bug occured. enter image description here

In another previous question: Will "mousedown" and "mousemove" change the cursor icon and how to prevent it?, @skmail suggested me to add preventDefault() on mousedown event.

It works! drag and dragstart event disappeared. But I still want to know: why drag and dragstart event can still be triggered when elements are configured as draggable=false? I mean there's almost nothing but hundreds of empty div. And they are all undraggable`... I'm really confused.

It would be very nice if you can further explain why preventDefault() can solve this problem? For now, the only thing I'm sure is that this unexpected drag operation is trigger by browser's default setting. Anyone have some hint?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source