Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <div class="widget-wrap">
  <h1>JS NOTICE BOARD</h1>
  
  <!--
  Enter text and "add" to create a new note.
  Drag-and-drop a note to rearrange.
  Double click on a note to edit.
  Hover over a note and click on "X" to delete it.
  -->
  
  <!-- (A) ADD/UPDATE NOTE -->
  <form id="noteform">
    <input type="text" id="notetxt" required disabled/>
    <input type="submit" id="notego" value="Add" disabled/>
  </form>
  
  <!-- (B) NOTICE BOARD -->
  <div id="board"></div>
  
  <!-- (X) VISIT CODE-BOXX -->
  <div id="code-boxx">
    Visit
    <a href="https://code-boxx.com/javascript-notice-board/" target="_blank">
      Code Boxx
    </a> for more details.
  </div>
</div>
              
            
!

CSS

              
                /* (A) ENTIRE PAGE */
* {
  font-family: arial, sans-serif;
  box-sizing: border-box;
}

/* (B) ADD NEW NOTE */
#noteform {
  display: flex;
  margin-bottom: 20px;
}
#notetxt { flex-grow: 1; }
#notetxt, #notego { border: 0; }
#notetxt { padding: 10px; }
#notego {
  padding: 10px 20px;
  font-size: 18px;
  color: #fff;
  background: #0e5ce9;
}

/* (C) NOTICE BOARD WRAPPER */
#board {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 20px;
}

/* (D) NOTES */
div.note {
  position: relative;
  padding: 15px;
  border: 2px solid #fdff8a;
  background: #fdff8a;
  box-shadow: 9px 11px 11px -2px rgba(0,0,0,0.4);
}

/* (E) DELETE BUTTON */
div.note .del {
  position: absolute;
  top: 5px; right: 5px;
  color: #ff5a5a;
  font-size: 20px;
  font-weight: 700;
  display: none;
}
div.note:hover .del { display: block; }

/* (F) EDIT NOTE */
div.note .txt input {
  padding: 5px;
  border: 0;
  background: #fff;
}
div.note .txt input:focus { outline-width: 0; }

/* (G) LOCK DRAG & DELETE WHEN EDITING */
#board div.lock {
  pointer-events: none;
  color: #818181;
  border: 1px solid #d3d3d3;
  background: #d3d3d3;
}
#board div.lock .del { display: none; }

/* (H) PREVENT DRAG LEAVE EVENT ON NOTE CHILD ELEMENTS */
#board div.drag .txt, #board div.drag .del { pointer-events: none; }
#board div.drag .del { display: none; }

/* (I) DRAG HIGHLIGHT */
#board div.hint {
  border: 2px dashed #ff8e68;
  background: #feffc5;
}
#board div.active {
  border: 2px dashed #ff0000;
  background: #fcff00;
}

/* (X) DOES NOT MATTER - COSMETICS */
body {
  display: flex;
  align-items: center; justify-content: center;
  min-height: 100vh;
  background-image: url(https://images.unsplash.com/photo-1585854467604-cf2080ccef31?crop=entropy&cs=tinysrgb&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTI5NjEwODA&ixlib=rb-1.2.1&q=80);
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
  text-align: center;
}

/* WIDGET */
.widget-wrap {
  width: 600px;
  padding: 30px;
  border-radius: 20px;
  background: rgba(170, 185, 255, 0.5);
}

/* FOOTER */
#code-boxx {
  font-weight: 600;
  margin-top: 30px;
}
#code-boxx a {
  display: inline-block;
  border: 0;
  padding: 5px;
  text-decoration: none;
  background: #b90a0a;
  color: #fff;
}
              
            
!

JS

              
                var board = {
  // (A) PROPERTIES
  notes : [],   // current list of notes
  hwrap : null, // html notice board wrapper
  hform: null,  // html add/update note form
  hadd : null,  // html add/update note text field
  hgo : null,   // html add/update note button
  hsel : null,  // current note being dragged or edited

  // (B) INITIALIZE NOTICE BOARD
  init : () => {
    // (B1) GET HTML ELEMENTS
    board.hwrap = document.getElementById("board");
    board.hform = document.getElementById("noteform");
    board.hadd = document.getElementById("notetxt");
    board.hgo = document.getElementById("notego");

    // (B2) LOAD & DRAW HTML NOTES
    let data = localStorage.getItem("notes");
    if (data !== null) { for (let n of JSON.parse(data)) {
      board.draw(n);
    }}

    // (B3) ENABLE ADD NEW NOTE
    board.hform.onsubmit = () => { return board.add(); };
    board.hadd.disabled = false;
    board.hgo.disabled = false;
  },

  // (C) HELPER - CREATE HTML NOTE
  draw : (note, first) => {
    // (C1) CREATE HTML NOTE
    let div = document.createElement("div");
    div.className = "note";
    div.draggable = true;
    div.innerHTML = `<div class="del" onclick="board.del(this.parentElement)">X</div> <div class="txt">${note}</div>`;

    // (C2) ON DRAG START - ADD DROPPABLE HINTS
    div.ondragstart = (e) => {
      board.hsel = e.target;
      for (let n of board.notes) {
        n.classList.add("drag");
        if (n != board.hsel) { n.classList.add("hint"); }
      }
    };

    // (C3) ON DRAG ENTER - HIGHLIGHT DROPZONE
    div.ondragenter = (e) => {
      if (div != board.hsel) { div.classList.add("active"); }
    };

    // (C4) DRAG LEAVE - REMOVE HIGHLIGHT DROPZONE
    div.ondragleave = (e) => {
      div.classList.remove("active");
    };

    // (C5) DRAG END - REMOVE ALL HIGHLIGHTS
    div.ondragend = (e) => { for (let n of board.notes) {
      n.classList.remove("drag");
      n.classList.remove("hint");
      n.classList.remove("active");
    }};

    // (C6) DRAG OVER - PREVENT DEFAULT "DROP", SO WE CAN DO OUR OWN
    div.ondragover = (e) => { e.preventDefault(); };

    // (C7) ON DROP - REORDER NOTES & SAVE
    div.ondrop = (e) => {
      // (C7-1) PREVENT DEFAULT BROWSER DROP ACTION
      e.preventDefault();

      if (e.target != board.hsel) {
        // (C7-2) GET CURRENT & DROPPED POSITIONS
        let idrag = 0, // index of currently dragged
            idrop = 0; // index of dropped location
        for (let i=0; i<board.notes.length; i++) {
          if (board.hsel == board.notes[i]) { idrag = i; }
          if (e.target == board.notes[i]) { idrop = i; }
        }

        // (C7-3) REORDER HTML NOTES
        if (idrag > idrop) {
          board.hwrap.insertBefore(board.hsel, e.target);
        } else {
          board.hwrap.insertBefore(board.hsel, e.target.nextSibling);
        }

        // (C7-4) REORDER & SAVE NOTES ARRAY
        board.save();
      }
    };

    // (C8) DOUBLE CLICK TO EDIT NOTE
    div.ondblclick = () => {
      // (C8-1) SELECTED NOTE
      board.hsel = div.querySelector(".txt");

      // (C8-2) LOCK - NO DRAG NO DELETE WHILE EDITING
      for (let n of board.notes) { n.classList.add("lock"); }

      // (C8-3) UPDATE NOTE FORM
      board.hadd.value = board.hsel.innerHTML;
      board.hgo.value = "Update";
      board.hform.onsubmit = () => { return board.update(); };
      // board.hadd.focus();
      board.hadd.select();
    };

    // (C9) DONE - PUSH INTO ARRAY & ATTACH TO CONTAINER
    if (first) {
      board.notes.unshift(div);
      board.hwrap.insertBefore(div, board.hwrap.firstChild);
    } else {
      board.notes.push(div);
      board.hwrap.appendChild(div);
    }
  },

  // (D) ADD NEW NOTE
  add : () => {
    board.draw(board.hadd.value, true);
    board.hadd.value = "";
    board.save();
    return false;
  },

  // (E) DELETE NOTE
  del : (note) => { if (confirm("Delete note?")) {
    note.remove();
    board.save();
  }},

  // (F) UPDATE NOTE
  update : () => {
    // (F1) UPDATE NOTE
    board.hsel.innerHTML = board.hadd.value;
    board.hadd.value = "";
    board.hgo.value = "Add";

    // (F2) "RESTORE" ADD NOTE FORM
    board.hform.onsubmit = () => { return board.add(); };

    // (F3) SAVE
    board.save();

    // (F4) UNLOCK - ALLOW DRAG & DELETE
    for (let n of board.notes) { n.classList.remove("lock"); }
    return false;
  },

  // (G) UPDATE & SAVE NOTES
  save : () => {
    // (G1) REORDER NOTES ARRAY
    let data = [];
    board.notes = [];
    for (let n of board.hwrap.getElementsByClassName("note")) {
      board.notes.push(n);
      data.push(n.querySelector(".txt").innerHTML);
    }

    // (G2) SAVE DATA
    localStorage.setItem("notes", JSON.stringify(data));
  }
};

window.addEventListener("DOMContentLoaded", board.init);

              
            
!
999px

Console