diff --git a/src/components/backpack/backpack.jsx b/src/components/backpack/backpack.jsx
index 04cdc293798d3d2217f9eaed7299505db951c3a1..f5f4500393bc73d80e888d7b7b90b97ad6cde567 100644
--- a/src/components/backpack/backpack.jsx
+++ b/src/components/backpack/backpack.jsx
@@ -10,14 +10,26 @@ import styles from './backpack.css';
 // TODO make sprite selector item not require onClick
 const noop = () => {};
 
-const dragTypeMap = {
+const dragTypeMap = { // Keys correspond with the backpack-server item types
     costume: DragConstants.BACKPACK_COSTUME,
     sound: DragConstants.BACKPACK_SOUND,
-    code: DragConstants.BACKPACK_CODE,
+    script: DragConstants.BACKPACK_CODE,
     sprite: DragConstants.BACKPACK_SPRITE
 };
 
-const Backpack = ({containerRef, contents, dragOver, error, expanded, loading, onToggle, onDelete}) => (
+const Backpack = ({
+    blockDragOver,
+    containerRef,
+    contents,
+    dragOver,
+    error,
+    expanded,
+    loading,
+    onToggle,
+    onDelete,
+    onMouseEnter,
+    onMouseLeave
+}) => (
     <div className={styles.backpackContainer}>
         <div
             className={styles.backpackHeader}
@@ -44,8 +56,12 @@ const Backpack = ({containerRef, contents, dragOver, error, expanded, loading, o
         </div>
         {expanded ? (
             <div
-                className={styles.backpackList}
+                className={classNames(styles.backpackList, {
+                    [styles.dragOver]: dragOver || blockDragOver
+                })}
                 ref={containerRef}
+                onMouseEnter={onMouseEnter}
+                onMouseLeave={onMouseLeave}
             >
                 {error ? (
                     <div className={styles.statusMessage}>
@@ -66,11 +82,7 @@ const Backpack = ({containerRef, contents, dragOver, error, expanded, loading, o
                         </div>
                     ) : (
                         contents.length > 0 ? (
-                            <div
-                                className={classNames(styles.backpackListInner, {
-                                    [styles.dragOver]: dragOver
-                                })}
-                            >
+                            <div className={styles.backpackListInner}>
                                 {contents.map(item => (
                                     <SpriteSelectorItem
                                         className={styles.backpackItem}
@@ -104,6 +116,7 @@ const Backpack = ({containerRef, contents, dragOver, error, expanded, loading, o
 );
 
 Backpack.propTypes = {
+    blockDragOver: PropTypes.bool,
     containerRef: PropTypes.func,
     contents: PropTypes.arrayOf(PropTypes.shape({
         id: PropTypes.string,
@@ -116,10 +129,13 @@ Backpack.propTypes = {
     expanded: PropTypes.bool,
     loading: PropTypes.bool,
     onDelete: PropTypes.func,
+    onMouseEnter: PropTypes.func,
+    onMouseLeave: PropTypes.func,
     onToggle: PropTypes.func
 };
 
 Backpack.defaultProps = {
+    blockDragOver: false,
     contents: [],
     dragOver: false,
     expanded: false,
diff --git a/src/components/blocks/blocks.css b/src/components/blocks/blocks.css
index 3d87405893c9268041744d1d5d2aecfa4bd4afc6..e0b07ce26cc7e5053d26a4db770f09f4304b021e 100644
--- a/src/components/blocks/blocks.css
+++ b/src/components/blocks/blocks.css
@@ -1,6 +1,22 @@
 @import "../../css/units.css";
 @import "../../css/colors.css";
 
+.blocks {
+    height: 100%;
+}
+
+.drag-over:after {
+    content: '';
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    opacity: 0.75;
+    background-color: #8cbcff;
+    transition: all 0.25s ease;
+}
+
 .blocks :global(.injectionDiv){
     position: absolute;
     top: 0;
diff --git a/src/components/blocks/blocks.jsx b/src/components/blocks/blocks.jsx
index 683da23c1f048eb39d84146cd72959a0593bc8d7..a812b039fb24079de76eac2896415b4286dca845 100644
--- a/src/components/blocks/blocks.jsx
+++ b/src/components/blocks/blocks.jsx
@@ -1,22 +1,27 @@
 import PropTypes from 'prop-types';
+import classNames from 'classnames';
 import React from 'react';
 import Box from '../box/box.jsx';
 import styles from './blocks.css';
 
 const BlocksComponent = props => {
     const {
-        componentRef,
+        containerRef,
+        dragOver,
         ...componentProps
     } = props;
     return (
         <Box
-            className={styles.blocks}
-            componentRef={componentRef}
+            className={classNames(styles.blocks, {
+                [styles.dragOver]: dragOver
+            })}
             {...componentProps}
+            componentRef={containerRef}
         />
     );
 };
 BlocksComponent.propTypes = {
-    componentRef: PropTypes.func
+    containerRef: PropTypes.func,
+    dragOver: PropTypes.bool
 };
 export default BlocksComponent;
diff --git a/src/containers/backpack.jsx b/src/containers/backpack.jsx
index 3f9b2dd5966bd66d0f991e22f28c0be874ff362d..cca9eaab2a62e8f50f4dc6469db8fee9498d5c15 100644
--- a/src/containers/backpack.jsx
+++ b/src/containers/backpack.jsx
@@ -8,7 +8,8 @@ import {
     deleteBackpackObject,
     soundPayload,
     costumePayload,
-    spritePayload
+    spritePayload,
+    codePayload
 } from '../lib/backpack-api';
 import DragConstants from '../lib/drag-constants';
 import DropAreaHOC from '../lib/drop-area-hoc.jsx';
@@ -28,10 +29,18 @@ class Backpack extends React.Component {
             'handleToggle',
             'handleDelete',
             'getBackpackAssetURL',
-            'refreshContents'
+            'refreshContents',
+            'handleMouseEnter',
+            'handleMouseLeave',
+            'handleBlockDragEnd',
+            'handleBlockDragUpdate'
         ]);
         this.state = {
-            dragOver: false,
+            // While the DroppableHOC manages drop interactions for asset tiles,
+            // we still need to micromanage drops coming from the block workspace.
+            // TODO this may be refactorable with the share-the-love logic in SpriteSelectorItem
+            blockDragOutsideWorkspace: false,
+            blockDragOverBackpack: false,
             error: false,
             offset: 0,
             itemsPerPage: 20,
@@ -50,12 +59,23 @@ class Backpack extends React.Component {
             storage._hasAddedBackpackSource = true;
         }
     }
+    componentDidMount () {
+        this.props.vm.addListener('BLOCK_DRAG_END', this.handleBlockDragEnd);
+        this.props.vm.addListener('BLOCK_DRAG_UPDATE', this.handleBlockDragUpdate);
+    }
+    componentWillUnmount () {
+        this.props.vm.removeListener('BLOCK_DRAG_END', this.handleBlockDragEnd);
+        this.props.vm.removeListener('BLOCK_DRAG_UPDATE', this.handleBlockDragUpdate);
+    }
     getBackpackAssetURL (asset) {
         return `${this.props.host}/${asset.assetId}.${asset.dataFormat}`;
     }
     handleToggle () {
         const newState = !this.state.expanded;
-        this.setState({expanded: newState, offset: 0});
+        this.setState({expanded: newState, offset: 0}, () => {
+            // Emit resize on window to get blocks to resize
+            window.dispatchEvent(new Event('resize'));
+        });
         if (newState) {
             this.refreshContents();
         }
@@ -72,6 +92,9 @@ class Backpack extends React.Component {
         case DragConstants.SPRITE:
             payloader = spritePayload;
             break;
+        case DragConstants.CODE:
+            payloader = codePayload;
+            break;
         }
         if (!payloader) return;
 
@@ -110,15 +133,47 @@ class Backpack extends React.Component {
                 });
         }
     }
+    handleBlockDragUpdate (isOutsideWorkspace) {
+        this.setState({
+            blockDragOutsideWorkspace: isOutsideWorkspace
+        });
+    }
+    handleMouseEnter () {
+        if (this.state.blockDragOutsideWorkspace) {
+            this.setState({
+                blockDragOverBackpack: true
+            });
+        }
+    }
+    handleMouseLeave () {
+        this.setState({
+            blockDragOverBackpack: false
+        });
+    }
+    handleBlockDragEnd (blocks) {
+        if (this.state.blockDragOverBackpack) {
+            this.handleDrop({
+                dragType: DragConstants.CODE,
+                payload: blocks
+            });
+        }
+        this.setState({
+            blockDragOverBackpack: false,
+            blockDragOutsideWorkspace: false
+        });
+    }
     render () {
         return (
             <DroppableBackpack
+                blockDragOver={this.state.blockDragOverBackpack}
                 contents={this.state.contents}
                 error={this.state.error}
                 expanded={this.state.expanded}
                 loading={this.state.loading}
                 onDelete={this.handleDelete}
                 onDrop={this.handleDrop}
+                onMouseEnter={this.handleMouseEnter}
+                onMouseLeave={this.handleMouseLeave}
                 onToggle={this.props.host ? this.handleToggle : null}
             />
         );
@@ -152,9 +207,13 @@ const getTokenAndUsername = state => {
 
 const mapStateToProps = state => Object.assign(
     {
-        vm: state.scratchGui.vm
+        dragInfo: state.scratchGui.assetDrag,
+        vm: state.scratchGui.vm,
+        blockDrag: state.scratchGui.blockDrag
     },
     getTokenAndUsername(state)
 );
 
-export default connect(mapStateToProps)(Backpack);
+const mapDispatchToProps = () => ({});
+
+export default connect(mapStateToProps, mapDispatchToProps)(Backpack);
diff --git a/src/containers/blocks.jsx b/src/containers/blocks.jsx
index 73a265be9de2c1407fb29b5291e0b55ae89eb938..89e926d3db7360f097b529863cb6b7ce19077ac8 100644
--- a/src/containers/blocks.jsx
+++ b/src/containers/blocks.jsx
@@ -16,6 +16,8 @@ import extensionData from '../lib/libraries/extensions/index.jsx';
 import CustomProcedures from './custom-procedures.jsx';
 import errorBoundaryHOC from '../lib/error-boundary-hoc.jsx';
 import {STAGE_DISPLAY_SIZES} from '../lib/layout-constants';
+import DropAreaHOC from '../lib/drop-area-hoc.jsx';
+import DragConstants from '../lib/drag-constants';
 
 import {connect} from 'react-redux';
 import {updateToolbox} from '../reducers/toolbox';
@@ -38,6 +40,10 @@ const addFunctionListener = (object, property, callback) => {
     };
 };
 
+const DroppableBlocks = DropAreaHOC([
+    DragConstants.BACKPACK_CODE
+])(BlocksComponent);
+
 class Blocks extends React.Component {
     constructor (props) {
         super(props);
@@ -47,6 +53,7 @@ class Blocks extends React.Component {
             'detachVM',
             'handleCategorySelected',
             'handleConnectionModalStart',
+            'handleDrop',
             'handleStatusButtonUpdate',
             'handleOpenSoundRecorder',
             'handlePromptStart',
@@ -404,6 +411,14 @@ class Blocks extends React.Component {
         ws.refreshToolboxSelection_();
         ws.toolbox_.scrollToCategoryById('myBlocks');
     }
+    handleDrop (dragInfo) {
+        fetch(dragInfo.payload.bodyUrl)
+            .then(response => response.json())
+            .then(blocks => {
+                this.props.vm.shareBlocksToTarget(blocks, this.props.vm.editingTarget.id);
+                this.props.vm.refreshWorkspace();
+            });
+    }
     render () {
         /* eslint-disable no-unused-vars */
         const {
@@ -427,9 +442,10 @@ class Blocks extends React.Component {
         } = this.props;
         /* eslint-enable no-unused-vars */
         return (
-            <div>
-                <BlocksComponent
+            <React.Fragment>
+                <DroppableBlocks
                     componentRef={this.setBlocks}
+                    onDrop={this.handleDrop}
                     {...props}
                 />
                 {this.state.prompt ? (
@@ -458,7 +474,7 @@ class Blocks extends React.Component {
                         onRequestClose={this.handleCustomProceduresClose}
                     />
                 ) : null}
-            </div>
+            </React.Fragment>
         );
     }
 }
diff --git a/src/lib/backpack-api.js b/src/lib/backpack-api.js
index 9453f197709fee3e1b06dbcb2c98d90f50ab1e49..4a6f7f6b24ccf2e9fba256fbed97d28ccf5c8aa7 100644
--- a/src/lib/backpack-api.js
+++ b/src/lib/backpack-api.js
@@ -2,6 +2,7 @@ import xhr from 'xhr';
 import costumePayload from './backpack/costume-payload';
 import soundPayload from './backpack/sound-payload';
 import spritePayload from './backpack/sprite-payload';
+import codePayload from './backpack/code-payload';
 
 const getBackpackContents = ({
     host,
@@ -78,5 +79,6 @@ export {
     deleteBackpackObject,
     costumePayload,
     soundPayload,
-    spritePayload
+    spritePayload,
+    codePayload
 };
diff --git a/src/lib/backpack/code-payload.js b/src/lib/backpack/code-payload.js
new file mode 100644
index 0000000000000000000000000000000000000000..6c190ea08bba98d173ca26c70eb409984142006d
--- /dev/null
+++ b/src/lib/backpack/code-payload.js
@@ -0,0 +1,16 @@
+import codeThumbnail from './code-thumbnail';
+
+const codePayload = code => {
+    const payload = {
+        type: 'script', // Needs to match backpack-server type name
+        name: 'code', // All code currently gets the same name
+        mime: 'application/json',
+        body: btoa(JSON.stringify(code)), // Base64 encode the json
+        thumbnail: codeThumbnail // TODO make code thumbnail dynamic
+    };
+
+    // Return a promise to make it consistent with other payload constructors like costume-payload
+    return new Promise(resolve => resolve(payload));
+};
+
+export default codePayload;
diff --git a/src/lib/backpack/code-thumbnail.js b/src/lib/backpack/code-thumbnail.js
new file mode 100644
index 0000000000000000000000000000000000000000..e657144bcb1c5c12a8fe99c6ffbb51a3234779df
--- /dev/null
+++ b/src/lib/backpack/code-thumbnail.js
@@ -0,0 +1,3 @@
+// image/jpeg base64 encoded code thumbnail image
+// eslint-disable-next-line max-len
+export default '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';
diff --git a/src/lib/drag-constants.js b/src/lib/drag-constants.js
index ce4da5af2a8d362feb8ddc81ff171331e3487e63..2fe13b0b0adb12e4f83b6c9da097efa2fcbc2895 100644
--- a/src/lib/drag-constants.js
+++ b/src/lib/drag-constants.js
@@ -2,6 +2,7 @@ export default {
     SOUND: 'SOUND',
     COSTUME: 'COSTUME',
     SPRITE: 'SPRITE',
+    CODE: 'CODE',
 
     BACKPACK_SOUND: 'BACKPACK_SOUND',
     BACKPACK_COSTUME: 'BACKPACK_COSTUME',
diff --git a/src/lib/drop-area-hoc.jsx b/src/lib/drop-area-hoc.jsx
index 9f44293e88cdaab98dcd80b0a8cdd4fde915b646..a5bfc649923c33f9242e2fc58e33c444529b74ed 100644
--- a/src/lib/drop-area-hoc.jsx
+++ b/src/lib/drop-area-hoc.jsx
@@ -4,7 +4,34 @@ import React from 'react';
 import omit from 'lodash.omit';
 import {connect} from 'react-redux';
 
+/**
+ * Higher Order Component to give components the ability to react to drag overs
+ * and drops of objects stored in the assetDrag redux state.
+ *
+ * Example: You want to enable MyComponent to receive drops from a drag type
+ *    Wrapped = DropAreaHOC([...dragTypes])(
+ *      <MyComponent />
+ *    )
+ *
+ * MyComponent now receives 2 new props
+ *      containerRef: a ref that must be set on the container element
+ *      dragOver: boolean if an asset is being dragged above the component
+ *
+ * Use the wrapped component:
+ *    <Wrapped onDrop={yourDropHandler} />
+ *
+ * NB: This HOC _only_ works with objects that drag using the assetDrag reducer.
+ *     This _does not_ handle drags for blocks coming from the workspace.
+ *
+ * @param {Array.<string>} dragTypes Types to respond to, from DragConstants
+ * @returns {function} The HOC, specialized for those drag types
+ */
 const DropAreaHOC = function (dragTypes) {
+    /**
+     * Return the HOC, specialized for the dragTypes
+     * @param {React.Component} WrappedComponent component to receive drop behaviors
+     * @returns {React.Component} component with drag over/drop behavior
+     */
     return function (WrappedComponent) {
         class DropAreaWrapper extends React.Component {
             constructor (props) {
@@ -46,6 +73,9 @@ const DropAreaHOC = function (dragTypes) {
             }
             setRef (el) {
                 this.ref = el;
+                if (this.props.componentRef) {
+                    this.props.componentRef(this.ref);
+                }
             }
             render () {
                 const componentProps = omit(this.props, ['onDrop', 'dragInfo']);
@@ -60,6 +90,7 @@ const DropAreaHOC = function (dragTypes) {
         }
 
         DropAreaWrapper.propTypes = {
+            componentRef: PropTypes.func,
             dragInfo: PropTypes.shape({
                 currentOffset: PropTypes.shape({
                     x: PropTypes.number,