Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's 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 it's URL and the proper URL extention.

+ 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

Save Automatically?

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

              
                <main>
	
	<section>
		<div class="alert alert-info">
			<b>Note: </b> to create a dropdown menu you first need to create a link
		</div>
	</section>
	
	<section>
		<div id="iJsonCreator" class="mt-2 mb-2"></div>
	</section>

	<section>
		<button id="new" class="btn btn-dark btn-sm">Add new</button>
		<button id="store" class="btn btn-primary btn-sm">Store</button>
	</section>

	<section>
		<p>Demo: </p>
		<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
			<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarTogglerDemo02" aria-controls="navbarTogglerDemo02" aria-expanded="false" aria-label="Toggle navigation">
				<span class="navbar-toggler-icon"></span>
			</button>
			<a class="navbar-brand" href="#!">Navbar</a>

			<div class="collapse navbar-collapse" id="navbarTogglerDemo02">
				<ul id="navigation" class="navbar-nav mr-auto mt-2 mt-md-0"></ul>
			</div>
		</nav>
	</section>

	<section>
		<p>Json: </p>
		<pre id="json" class="bg-dark text-light w-100 overflow-auto p-2" style="max-height:20rem"></pre>
	</section>
</main>

              
            
!

CSS

              
                [draggable] {
  -moz-user-select: none;
  -khtml-user-select: none;
  -webkit-user-select: none;
  user-select: none;
  /* Required to make elements draggable in old WebKit */
  -khtml-user-drag: element;
  -webkit-user-drag: element;
  padding: 0.2em;
  width: 42em;
  overflow: hidden;
  margin: 5px;
}
@media (min-width: 360px) {
  [draggable] {
    width: 100%;
  }
  #iJsonCreator * {
    display: block;
  }
}
#iJsonCreator {
  margin: 1rem auto;
}
#iJsonCreator input,
#iJsonCreator select,
#iJsonCreator button {
  display: inline-block;
  height: 2rem;
  box-sizing: border-box;
  width: calc(100% / 5 - 1.25rem);
  margin: 0 0.2rem;
	border: 1px solid #eeeeee;
	background: #ffffff;
	color: #414141;
  float: left;
}
#iJsonCreator button {
  border-radius: 2px;
  background: #f55;
  border: 1px solid #f55;
  color: white;
  padding: 0;
	margin: 0;
	min-width: 1rem;
	min-height: 1rem;
	max-width: 2rem;
}
#iJsonCreator .key {
	overflow: hidden;
	background: #fff;
	border: 2px dashed #e7e7e7;
	padding: 0.4rem;
}
#iJsonCreator .key span {
  user-select: none;
  display: block;
  text-align: center;
  float: left;
  margin: 0;
  margin-right: 0.2rem;
  padding: 0;
  cursor: pointer;
  min-width: 1.9rem;
  min-height: 1.9rem;
  line-height: 1.9rem;
  position: relative;
  overflow: hidden;
	background: #2196f3;
	border: 1px solid #1565c0;
	color: #ffffff;
}

.drag-over {
	background:#f88 !important;
  border-color: #f55 !important;
  transition: background 500ms ease;
}
main{
	margin: 3rem auto;
	max-width:50rem;
}
main section{
	margin-bottom:2rem;
}

main textarea {
	width:100%;
	min-height:20rem;
	resize:none;
}
              
            
!

JS

              
                /**
 * iMenu editor
 */
const iMenu = {
	/**
	 * Create elements
	 */
	createElement(element, where, args) {
		let d = document.createElement(element);
		if (args)
			for (const [k, v] of Object.entries(args)) d[k] = v;
		where.appendChild(d);
		return d;
	},
	/**
	 * Create Events for drag and drop
	 */
	createEvents(elem) {
		// short fn
		const listen = (el, fn) => elem.addEventListener(el, fn);
		// events
		listen("dragstart", this.handleDragStart);
		listen("dragenter", this.handleDragEnter);
		listen("dragover", this.handleDragOver);
		listen("dragleave", this.handleDragLeave);
		listen("drop", this.handleDrop);
		listen("dragend", this.handleDragEnd);
	},
	/**
	 * Create drag and drop html list
	 */
	createList(sel, n, t, a, p, u) {
		// create vars
		let container, btnDrag, iName, iTarget, iAlt, iParent, iUrl, btnClose;
		// container
		container = this.createElement("div", sel, {
			className: "key",
			draggable: true
		});
		// init drag events
		this.createEvents(container);
		// drag button
		btnDrag = this.createElement("span", container, {
			innerHTML: "☰",
			className: "drag"
		});
		// create input key
		iName = this.createElement("input", container, {
			type: "text",
			className: "input-key",
			value: n,
			placeholder: "Name"
		});
		// create select type
		iTarget = this.createElement("select", container, {
			className: "input-select",
			onchange: function(evt) {
				//console.log(evt.target.value);
			}
		});
		// generate select options
		let array = ["none", "_blank", "_self", "_parent", "_top", "framename"];
		for (let i = 0; i < array.length; i++) {
			let options = this.createElement("option", iTarget, {
				selected: array[i] === t ? true : false,
				value: array[i],
				text: array[i]
			});
		}
		// create input value
		iAlt = this.createElement("input", container, {
			value: a,
			className: "input-val",
			type: "text",
			placeholder: "Description"
		});
		// create input value
		iParent = this.createElement("input", container, {
			value: p,
			className: "input-val",
			type: "text",
			placeholder: "Parent"
		});
		// create input value
		iUrl = this.createElement("input", container, {
			value: u,
			className: "input-val",
			type: "text",
			placeholder: "The url"
		});
		// create btn close
		btnClose = this.createElement("button", container, {
			className: "btn btn-danger",
			innerHTML: "&times;",
			onclick: function() {
				this.parentElement.remove();
			}
		});
	},
	/**
	 * Import json elements and create list
	 */
	importList(elem, file) {
		let self = this,
			arr = Array.prototype.slice.call(file);
		arr.map(function(item) {
			let vars = elem;
			self.createList(
				elem,
				item.name,
				item.target,
				item.alt,
				item.parent,
				item.url
			);
		});
	},
	/**
	 * Convert html list to json data
	 */
	exportList() {
		let selectors = document.querySelectorAll(".key"),
			arr = Array.prototype.slice.call(selectors),
			objs = [];

		arr.map(function(item) {
			if (typeof item.children[1] !== "undefined") {
				objs.push({
					name: item.children[1].value,
					target: item.children[2].value,
					alt: item.children[3].value,
					parent: item.children[4].value,
					url: item.children[5].value
				});
			}
		});
		return objs;
	},
	/**
	 * Static method for drag & drop functions
	 */
	setValues(element, obj) {
		const setVal = (k, v) => (element.children[k].value = v);
		setVal(1, obj.name);
		setVal(2, obj.target);
		setVal(3, obj.alt);
		setVal(4, obj.parent);
		setVal(5, obj.url);
	},
	/**
	 * Drag start event read/write mode.
	 */
	handleDragStart(e) {
		// short fn
		const child = (el) => e.target.children[el].value;
		// get global obj
		self.obj = this;
		// set array
		let arr = {
			name: child(1),
			target: child(2),
			alt: child(3),
			parent: child(4),
			url: child(5)
		};
		// transfer json data
		e.dataTransfer.setData("arr", JSON.stringify(arr));
	},
	/**
	 * Drag & Drop over
	 */
	handleDragOver(e) {
		if (e.preventDefault) e.preventDefault();
		// check if is draggable
		if (e.target.getAttribute("draggable")) {
			e.dataTransfer.dropEffect = "move";
			e.target.className = "key drag-over";
		}
		return false;
	},
	/**
	 * Drag & Drop enter
	 */
	handleDragEnter(e) {
		// check if is draggable
		if (e.target.getAttribute("draggable")) {
			e.target.className = "key drag-drop";
		}
	},
	/**
	 * Drag & Drop leave
	 */
	handleDragLeave(e) {
		// check if is draggable
		if (e.target.getAttribute("draggable")) {
			e.target.className = "key drag-move";
		}
	},
	/**
	 * Drag & Drop drop read only mode.
	 */
	handleDrop(e) {
		let obj = self.obj;
		if (e.stopPropagation) e.stopPropagation();
		// check if is draggable
		if (!e.target.getAttribute("draggable")) return false;
		// exists global obj ?
		if (obj != this) {
			const child = (el) => e.target.children[el].value;
			// get old data
			let oldData = {
				name: child(1),
				target: child(2),
				alt: child(3),
				parent: child(4),
				url: child(5)
			};
			let newData = JSON.parse(e.dataTransfer.getData("arr"));
			// set values in the new place
			iMenu.setValues(obj, oldData);
			// set values in the old place
			iMenu.setValues(e.target, newData);
		}
		return false;
	},
	/**
	 * Drag & Drop end
	 */
	handleDragEnd(e) {
		// get all key and remove drag classes
		let cols = document.querySelectorAll("[draggable]"),
			arr = Array.prototype.slice.call(cols);
		arr.map((col) => {
			col.className = "key";
		});
	}
};

// demo
let data = '[{"name":"Home","target":"none","alt":"this is home","parent":"","url":"./home"},{"name":"Portfolio","target":"none","alt":"Portfolio desc","parent":"","url":"#"},{"name":"Blog","target":"_blank","alt":"this is a example external","parent":"","url":"https://example.com"},{"name":"About","target":"none","alt":"About Me","parent":"","url":"./about"},{"name":"Portfolio-3","target":"none","alt":"this is a example","parent":"Portfolio","url":"./portfolio/portfolio-3"},{"name":"Portfolio-1","target":"none","alt":"Portfolio-1 desc","parent":"Portfolio","url":"./portfolio/portfolio-1"},{"name":"Portfolio-2","target":"none","alt":"Portfolio-2 desc","parent":"Portfolio","url":"./portfolio/portfolio-2"}]';

// import demo
iMenu.importList(window.iJsonCreator, JSON.parse(data));

// create menu
storeData();

// on click add new
window.new.onclick = () => {
	iMenu.createList(window.iJsonCreator, "Example", "_blank", "test", "", "https://monchovarela.es");
};

// store
window.store.onclick = () => storeData();

// store fn
function storeData() {
	createNavigation(iMenu.exportList());
	window.json.textContent = JSON.stringify(iMenu.exportList(), null, 2);
}
// create nav
function createNavigation(data) {
	// get the new array
	let arr = regenerateData(data);
	let html = "";
	// map
	[...arr].map((item, key) => {
		// if child exists create dropdown
		if (item.child.length > 0) {
			html += `<li class="nav-item dropdown">
                <a  class="nav-link dropdown-toggle" href="#" id="nav-${key}" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
                    href="${item.url}" 
                    target="${item.target}" 
                    title="${item.alt}">
                    ${item.name}
                </a>
                <div class="dropdown-menu" aria-labelledby="nav-${key}">`;
			// map child to create dropdown-item
			[...item.child].map((chld) => {
				html += `<a class="dropdown-item"
										href="${chld.url}" 
										target="${chld.target}" 
										title="${chld.alt}">
										${chld.name}
								</a>`;
			});
			html += `</div></li>`;
		} else {
			// if parent not exists
			if (!item.parent) {
				html += `<li class="nav-item">
                    <a 	class="nav-link"
                        href="${item.url}" 
                        target="${item.target}" 
                        title="${item.alt}">
                        ${item.name}
                    </a>
                </li>`;
			}
		}
	});
	let output = document.getElementById("navigation");
	output.innerHTML = html;
}

// create new array with iJson data
function regenerateData(data) {
	let arr = new Set();
	data.map((item) => {

		// show only childs
		const parents = data.filter((d) => d.parent === item.name);
		// add new array with childs
		arr.add({
			name: item.name,
			target: item.target,
			alt: item.alt,
			url: item.url,
			parent: item.parent,
			// add childs
			child: parents
		});
	});
	return arr;
}
              
            
!
999px

Console