diff --git a/package.json b/package.json
index 556f0c72..65f866dc 100644
--- a/package.json
+++ b/package.json
@@ -74,6 +74,7 @@
     "pako": "^1.0.5",
     "prop-types": "^15.5.10",
     "react": "^15.6.0",
+    "react-beautiful-dnd": "^4.0.1",
     "react-dnd": "^2.1.4",
     "react-dnd-html5-backend": "^2.1.2",
     "react-dom": "^15.6.0",
diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js
index 251c6522..15f56c00 100644
--- a/src/components/structures/RoomSubList.js
+++ b/src/components/structures/RoomSubList.js
@@ -20,8 +20,8 @@ limitations under the License.
 var React = require('react');
 var ReactDOM = require('react-dom');
 var classNames = require('classnames');
-var DropTarget = require('react-dnd').DropTarget;
 var sdk = require('matrix-react-sdk');
+import { Droppable } from 'react-beautiful-dnd';
 import { _t } from 'matrix-react-sdk/lib/languageHandler';
 var dis = require('matrix-react-sdk/lib/dispatcher');
 var Unread = require('matrix-react-sdk/lib/Unread');
@@ -32,6 +32,7 @@ var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/A
 import Modal from 'matrix-react-sdk/lib/Modal';
 import { KeyCode } from 'matrix-react-sdk/lib/Keyboard';
 
+
 // turn this on for drop & drag console debugging galore
 var debug = false;
 
@@ -326,9 +327,7 @@ var RoomSubList = React.createClass({
         });
     },
 
-    calcManualOrderTagData: function(room) {
-        const index = this.state.sortedList.indexOf(room);
-
+    calcManualOrderTagData: function(index) {
         // we sort rooms by the lexicographic ordering of the 'order' metadata on their tags.
         // for convenience, we calculate this for now a floating point number between 0.0 and 1.0.
 
@@ -375,12 +374,14 @@ var RoomSubList = React.createClass({
     makeRoomTiles: function() {
         var self = this;
         var DNDRoomTile = sdk.getComponent("rooms.DNDRoomTile");
-        return this.state.sortedList.map(function(room) {
+        return this.state.sortedList.map(function(room, index) {
             // XXX: is it evil to pass in self as a prop to RoomTile?
             return (
                 <DNDRoomTile
+                    index={index} // For DND
                     room={ room }
                     roomSubList={ self }
+                    tagName={self.props.tagName}
                     key={ room.roomId }
                     collapsed={ self.props.collapsed || false}
                     unread={ Unread.doesRoomHaveUnreadMessages(room) }
@@ -566,12 +567,18 @@ var RoomSubList = React.createClass({
                           </TruncatedList>;
             }
 
-            return connectDropTarget(
-                <div>
-                    { this._getHeaderJsx() }
-                    { subList }
-                </div>
-            );
+            const subListContent = <div>
+                { this._getHeaderJsx() }
+                { subList }
+            </div>;
+
+            return this.props.editable ? <Droppable droppableId={"room-sub-list-droppable_" + this.props.tagName}>
+                { (provided, snapshot) => (
+                    <div ref={provided.innerRef}>
+                        { subListContent }
+                    </div>
+                ) }
+            </Droppable> : subListContent;
         }
         else {
             var Loader = sdk.getComponent("elements.Spinner");
@@ -585,11 +592,4 @@ var RoomSubList = React.createClass({
     }
 });
 
-// Export the wrapped version, inlining the 'collect' functions
-// to more closely resemble the ES7
-module.exports =
-DropTarget('RoomTile', roomListTarget, function(connect) {
-    return {
-        connectDropTarget: connect.dropTarget(),
-    }
-})(RoomSubList);
+module.exports = RoomSubList;
diff --git a/src/components/views/rooms/DNDRoomTile.js b/src/components/views/rooms/DNDRoomTile.js
index 430906d2..1adb2a79 100644
--- a/src/components/views/rooms/DNDRoomTile.js
+++ b/src/components/views/rooms/DNDRoomTile.js
@@ -14,227 +14,50 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-'use strict';
-
 import React from 'react';
-import {DragSource} from 'react-dnd';
-import {DropTarget} from 'react-dnd';
-
-import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
-import sdk from 'matrix-react-sdk';
-import { _t } from 'matrix-react-sdk/lib/languageHandler';
+import { Draggable } from 'react-beautiful-dnd';
 import RoomTile from 'matrix-react-sdk/lib/components/views/rooms/RoomTile';
-import * as Rooms from 'matrix-react-sdk/lib/Rooms';
-import Modal from 'matrix-react-sdk/lib/Modal';
 
-/**
- * Defines a new Component, DNDRoomTile that wraps RoomTile, making it draggable.
- * Requires extra props:
- *   roomSubList: React.PropTypes.object.isRequired,
- *   refreshSubList: React.PropTypes.func.isRequired,
- */
+export default class DNDRoomTile extends React.Component {
+    constructor() {
+        super();
+        this.getStyle = this.getStyle.bind(this);
+    }
 
-/**
- * Specifies the drag source contract.
- * Only `beginDrag` function is required.
- */
-var roomTileSource = {
-    canDrag: function(props, monitor) {
-        return props.roomSubList.props.editable;
-    },
-
-    beginDrag: function (props) {
-        // Return the data describing the dragged item
-        var item = {
-            room: props.room,
-            originalList: props.roomSubList,
-            originalIndex: props.roomSubList.findRoomTile(props.room).index,
-            targetList: props.roomSubList, // at first target is same as original
-            // lastTargetRoom: null,
-            // lastYOffset: null,
-            // lastYDelta: null,
+    getStyle(isDragging) {
+        const result = {
+            transform: isDragging ? "scale(1.05, 1.05)" : "none",
+            transition: "transform 0.2s",
         };
-
-        if (props.roomSubList.debug) console.log("roomTile beginDrag for " + item.room.roomId);
-
-        // doing this 'correctly' with state causes react-dnd to break seemingly due to the state transitions
-        props.room._dragging = true;
-
-        return item;
-    },
-
-    endDrag: function (props, monitor, component) {
-        var item = monitor.getItem();
-
-        if (props.roomSubList.debug) console.log("roomTile endDrag for " + item.room.roomId + " with didDrop=" + monitor.didDrop());
-
-        props.room._dragging = false;
-        if (monitor.didDrop()) {
-            if (props.roomSubList.debug) console.log("force updating component " + item.targetList.props.label);
-            item.targetList.forceUpdate(); // as we're not using state
-        }
-
-        const prevTag = item.originalList.props.tagName;
-        const newTag = item.targetList.props.tagName;
-
-        if (monitor.didDrop() && item.targetList.props.editable) {
-            // Evil hack to get DMs behaving
-            if ((prevTag === undefined && newTag === 'im.vector.fake.direct') ||
-                (prevTag === 'im.vector.fake.direct' && newTag === undefined)
-            ) {
-                Rooms.guessAndSetDMRoom(
-                    item.room, newTag === 'im.vector.fake.direct',
-                ).done(() => {
-                    item.originalList.removeRoomTile(item.room);
-                }, (err) => {
-                    const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
-                    console.error("Failed to set direct chat tag " + err);
-                    Modal.createTrackedDialog('Failed to set direct chat tag', '', ErrorDialog, {
-                        title: _t('Failed to set direct chat tag'),
-                        description: ((err && err.message) ? err.message : _t('Operation failed')),
-                    });
-                });
-                return;
-            }
-
-            // More evilness: We will still be dealing with moving to favourites/low prio,
-            // but we avoid ever doing a request with 'im.vector.fake.direct`.
-
-            // if we moved lists, remove the old tag
-            if (prevTag && prevTag !== 'im.vector.fake.direct' &&
-                item.targetList !== item.originalList
-            ) {
-                // commented out attempts to set a spinner on our target component as component is actually
-                // the original source component being dragged, not our target.  To fix we just need to
-                // move all of this to endDrop in the target instead.  FIXME later.
-
-                //component.state.set({ spinner: component.state.spinner ? component.state.spinner++ : 1 });
-                MatrixClientPeg.get().deleteRoomTag(item.room.roomId, prevTag).finally(function() {
-                    //component.state.set({ spinner: component.state.spinner-- });
-                }).catch(function(err) {
-                    var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
-                    console.error("Failed to remove tag " + prevTag + " from room: " + err);
-                    Modal.createTrackedDialog('Failed to remove tag from room', '', ErrorDialog, {
-                        title: _t('Failed to remove tag %(tagName)s from room', {tagName: prevTag}),
-                        description: ((err && err.message) ? err.message : _t('Operation failed')),
-                    });
-                });
-            }
-
-            var newOrder= {};
-            if (item.targetList.props.order === 'manual') {
-                newOrder['order'] = item.targetList.calcManualOrderTagData(item.room);
-            }
-
-            // if we moved lists or the ordering changed, add the new tag
-            if (newTag && newTag !== 'im.vector.fake.direct' &&
-                (item.targetList !== item.originalList || newOrder)
-            ) {
-                MatrixClientPeg.get().setRoomTag(item.room.roomId, newTag, newOrder).catch(function(err) {
-                    var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
-                    console.error("Failed to add tag " + newTag + " to room: " + err);
-                    Modal.createTrackedDialog('Failed to add tag to room', '', ErrorDialog, {
-                        title: _t('Failed to add tag %(tagName)s to room', {tagName: newTag}),
-                        description: ((err && err.message) ? err.message : _t('Operation failed')),
-                    });
-                });
-            }
-        }
-        else {
-            // cancel the drop and reset our original position
-            if (props.roomSubList.debug) console.log("cancelling drop & drag");
-            props.roomSubList.moveRoomTile(item.room, item.originalIndex);
-            if (item.targetList && item.targetList !== item.originalList) {
-                item.targetList.removeRoomTile(item.room);
-            }
-        }
+        return result;
     }
-};
 
-var roomTileTarget = {
-    canDrop: function() {
-        return false;
-    },
+    render() {
+        const props = this.props;
 
-    hover: function(props, monitor) {
-        var item = monitor.getItem();
-        //var off = monitor.getClientOffset();
-        // console.log("hovering on room " + props.room.roomId + ", isOver=" + monitor.isOver());
-
-        //console.log("item.targetList=" + item.targetList + ", roomSubList=" + props.roomSubList);
-
-        var switchedTarget = false;
-        if (item.targetList !== props.roomSubList) {
-            // we've switched target, so remove the tile from the previous target.
-            // n.b. the previous target might actually be the source list.
-            if (props.roomSubList.debug) console.log("switched target sublist");
-            switchedTarget = true;
-            item.targetList.removeRoomTile(item.room);
-            item.targetList = props.roomSubList;
-        }
-
-        if (!item.targetList.props.editable) return;
-
-        if (item.targetList.props.order === 'manual') {
-            if (item.room.roomId !== props.room.roomId && props.room !== item.lastTargetRoom) {
-                // find the offset of the target tile in the list.
-                var roomTile = props.roomSubList.findRoomTile(props.room);
-                // shuffle the list to add our tile to that position.
-                props.roomSubList.moveRoomTile(item.room, roomTile.index);
-            }
-
-            // stop us from flickering between our droptarget and the previous room.
-            // whenever the cursor changes direction we have to reset the flicker-damping.
-/*
-            var yDelta = off.y - item.lastYOffset;
-
-            if ((yDelta > 0 && item.lastYDelta < 0) ||
-                (yDelta < 0 && item.lastYDelta > 0))
-            {
-                // the cursor changed direction - forget our previous room
-                item.lastTargetRoom = null;
-            }
-            else {
-                // track the last room we were hovering over so we can stop
-                // bouncing back and forth if the droptarget is narrower than
-                // the other list items.  The other way to do this would be
-                // to reduce the size of the hittarget on the list items, but
-                // can't see an easy way to do that.
-                item.lastTargetRoom = props.room;
-            }
-
-            if (yDelta) item.lastYDelta = yDelta;
-            item.lastYOffset = off.y;
-*/
-        }
-        else if (switchedTarget) {
-            if (!props.roomSubList.findRoomTile(item.room).room) {
-                // add to the list in the right place
-                props.roomSubList.moveRoomTile(item.room, 0);
-            }
-            // we have to sort the list whatever to recalculate it
-            props.roomSubList.sortList();
-        }
-    },
-};
-
-// Export the wrapped version, inlining the 'collect' functions
-// to more closely resemble the ES7
-module.exports =
-DropTarget('RoomTile', roomTileTarget, function(connect, monitor) {
-    return {
-        // Call this function inside render()
-        // to let React DnD handle the drag events:
-        connectDropTarget: connect.dropTarget(),
-        isOver: monitor.isOver(),
+        return <div>
+            <Draggable
+                key={props.room.roomId}
+                draggableId={props.tagName + '_' + props.room.roomId}
+                index={props.index}
+            >
+                { (provided, snapshot) => {
+                    return (
+                        <div>
+                            <div
+                                ref={provided.innerRef}
+                                {...provided.draggableProps}
+                                {...provided.dragHandleProps}
+                            >
+                                <div style={this.getStyle(snapshot.isDragging)}>
+                                    <RoomTile {...props} />
+                                </div>
+                            </div>
+                            { provided.placeholder }
+                        </div>
+                    );
+                } }
+            </Draggable>
+        </div>;
     }
-})(
-DragSource('RoomTile', roomTileSource, function(connect, monitor) {
-    return {
-        // Call this function inside render()
-        // to let React DnD handle the drag events:
-        connectDragSource: connect.dragSource(),
-        // You can ask the monitor about the current drag state:
-        isDragging: monitor.isDragging()
-    };
-})(RoomTile));
+}
diff --git a/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomTile.scss b/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomTile.scss
index 842228b9..c9e7022e 100644
--- a/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomTile.scss
+++ b/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomTile.scss
@@ -20,6 +20,8 @@ limitations under the License.
     font-size: 13px;
     display: block;
     height: 34px;
+
+    background-color: $secondary-accent-color;
 }
 
 .mx_RoomTile_tooltip {
diff --git a/src/skins/vector/css/themes/_base.scss b/src/skins/vector/css/themes/_base.scss
index d5e862ae..35fc1a79 100644
--- a/src/skins/vector/css/themes/_base.scss
+++ b/src/skins/vector/css/themes/_base.scss
@@ -104,6 +104,7 @@ $roomtile-name-color: rgba(69, 69, 69, 0.8);
 $roomtile-selected-bg-color: rgba(255, 255, 255, 0.8);
 $roomtile-focused-bg-color: rgba(255, 255, 255, 0.9);
 
+$roomsublist-background: #badece;
 $roomsublist-label-fg-color: $h3-color;
 $roomsublist-label-bg-color: $tertiary-accent-color;
 $roomsublist-chevron-color: $accent-color;
diff --git a/src/skins/vector/css/themes/_dark.scss b/src/skins/vector/css/themes/_dark.scss
index 60ffeca8..b0ca76b8 100644
--- a/src/skins/vector/css/themes/_dark.scss
+++ b/src/skins/vector/css/themes/_dark.scss
@@ -100,9 +100,10 @@ $rte-code-bg-color: #000;
 // ********************
 
 $roomtile-name-color: rgba(186, 186, 186, 0.8);
-$roomtile-selected-bg-color: rgba(255, 255, 255, 0.05);
+$roomtile-selected-bg-color: #333;
 $roomtile-focused-bg-color: rgba(255, 255, 255, 0.2);
 
+$roomsublist-background: #222;
 $roomsublist-label-fg-color: $h3-color;
 $roomsublist-label-bg-color: $tertiary-accent-color;
 $roomsublist-chevron-color: $accent-color;
diff --git a/src/skins/vector/css/vector-web/structures/_RoomSubList.scss b/src/skins/vector/css/vector-web/structures/_RoomSubList.scss
index db1fb170..a2863460 100644
--- a/src/skins/vector/css/vector-web/structures/_RoomSubList.scss
+++ b/src/skins/vector/css/vector-web/structures/_RoomSubList.scss
@@ -18,6 +18,8 @@ limitations under the License.
     display: table;
     table-layout: fixed;
     width: 100%;
+
+    background-color: $roomsublist-background;
 }
 
 .mx_RoomSubList_labelContainer {
@@ -155,6 +157,8 @@ limitations under the License.
     position: relative;
     cursor: pointer;
     font-size: 13px;
+
+    background-color: $secondary-accent-color;
 }
 
 .collapsed .mx_RoomSubList_ellipsis {
diff --git a/src/skins/vector/themes/status/css/_status.scss b/src/skins/vector/themes/status/css/_status.scss
index ed60b83d..be4c3c7f 100644
--- a/src/skins/vector/themes/status/css/_status.scss
+++ b/src/skins/vector/themes/status/css/_status.scss
@@ -160,6 +160,7 @@ $roomtile-name-color: #ffffff;
 $roomtile-selected-bg-color: #465561;
 $roomtile-focused-bg-color: #6d8597;
 
+$roomsublist-background: #465561;
 $roomsublist-label-fg-color: #ffffff;
 $roomsublist-label-bg-color: $secondary-accent-color;
 $roomsublist-chevron-color: #ffffff;