Clipboard preview

by Comandeer

HTML

<div contenteditable id="preview"></div>
<dl id="details"></dl>

CSS

#preview {
	border: 5px dashed red;
	padding: 10px;
	min-height: 2em;
}
#preview:empty::after {
	content: 'Paste or drop inside me!';
}
#preview:focus-within::after {
	content: '';
}

dt {
	font-weight: bold;
	font-size: bigger;
}

dd {
	padding-bottom: 1em;
	margin-bottom: 1em;
	border-bottom: 2px solid black;
}

JavaScript

const preview = document.querySelector( '#preview' );
const details = document.querySelector( '#details' );

preview.addEventListener( 'paste', handleDataTransferEvent );
preview.addEventListener( 'drop', handleDataTransferEvent );

function handleDataTransferEvent( evt ) {
	const data = evt.clipboardData || evt.dataTransfer;
	
	if ( evt.type === 'drop' ) {
		evt.preventDefault();
	}
	
	details.innerHTML = '';
	
	[ ...data.items ].forEach( ( item ) => {
		const type = item.type;
		
		convertToHTML( item, ( html ) => {
			details.insertAdjacentHTML( 'beforeend', `<dt>${ type }</dt><dd>${ html }</dd>` );	
		} );
	} );
	
	[ ...data.files ].forEach( ( file, i ) => {
		details.insertAdjacentHTML( 'beforeend', `<dt>File #${ i }</dt><dd>${ file.name } (${ file.size }B)<br>${ handleFile( file ) }</dd>` );
	} )
}

function convertToHTML( item, callback ) {
	if ( item.type.startsWith( 'text/' ) ) {
		return item.getAsString( callback );
	}
	
	const file = item.getAsFile( ( file ) => {
		const image = handleFile( file );
		
		callback( image );
	} );
}

function handleFile( file ) {
	const url = URL.createObjectURL( file );
	
	if ( !file.type.startsWith( 'image') ) {
		return url;
	}
	
	return `<img src="${ url }" alt="">`;
}