diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -7,11 +7,11 @@
  */
 return array(
   'names' => array(
-    'core.pkg.css' => 'c7fc5aec',
-    'core.pkg.js' => '10275c16',
+    'core.pkg.css' => '15cd7345',
+    'core.pkg.js' => '00dbc918',
     'darkconsole.pkg.js' => 'e7393ebb',
     'differential.pkg.css' => 'b3eea3f5',
-    'differential.pkg.js' => '4b7d8f19',
+    'differential.pkg.js' => 'd574cebf',
     'diffusion.pkg.css' => '91c5d3a6',
     'diffusion.pkg.js' => '3a9a8bfa',
     'maniphest.pkg.css' => '4845691a',
@@ -124,7 +124,7 @@
     'rsrc/css/phui/phui-badge.css' => '3baef8db',
     'rsrc/css/phui/phui-big-info-view.css' => 'bd903741',
     'rsrc/css/phui/phui-box.css' => '5c8387cf',
-    'rsrc/css/phui/phui-button.css' => 'a64a8de6',
+    'rsrc/css/phui/phui-button.css' => '287efbfa',
     'rsrc/css/phui/phui-chart.css' => '6bf6f78e',
     'rsrc/css/phui/phui-crumbs-view.css' => '6b813619',
     'rsrc/css/phui/phui-curtain-view.css' => '7148ae25',
@@ -230,7 +230,7 @@
     'rsrc/externals/javelin/ext/view/__tests__/ViewInterpreter.js' => '7a94d6a5',
     'rsrc/externals/javelin/ext/view/__tests__/ViewRenderer.js' => '6ea96ac9',
     'rsrc/externals/javelin/lib/Cookie.js' => '62dfea03',
-    'rsrc/externals/javelin/lib/DOM.js' => '805b806a',
+    'rsrc/externals/javelin/lib/DOM.js' => '5e5acdda',
     'rsrc/externals/javelin/lib/History.js' => 'd4505101',
     'rsrc/externals/javelin/lib/JSON.js' => '69adf288',
     'rsrc/externals/javelin/lib/Leader.js' => 'fea0eb47',
@@ -457,7 +457,7 @@
     'rsrc/js/application/uiexample/gesture-example.js' => '558829c2',
     'rsrc/js/application/uiexample/notification-example.js' => '8ce821c5',
     'rsrc/js/core/Busy.js' => '59a7976a',
-    'rsrc/js/core/DragAndDropFileUpload.js' => '58dea2fa',
+    'rsrc/js/core/DragAndDropFileUpload.js' => 'd1d13c52',
     'rsrc/js/core/DraggableList.js' => '5a13c79f',
     'rsrc/js/core/FileUpload.js' => '680ea2c8',
     'rsrc/js/core/Hovercard.js' => '1bd28176',
@@ -515,14 +515,14 @@
     'rsrc/js/core/behavior-watch-anchor.js' => '9f36c42d',
     'rsrc/js/core/behavior-workflow.js' => '0a3f3021',
     'rsrc/js/core/phtize.js' => 'd254d646',
-    'rsrc/js/phui/behavior-phui-dropdown-menu.js' => '54733475',
+    'rsrc/js/phui/behavior-phui-dropdown-menu.js' => '3d948804',
     'rsrc/js/phui/behavior-phui-file-upload.js' => 'b003d4fb',
     'rsrc/js/phui/behavior-phui-object-box-tabs.js' => '2bfa2836',
     'rsrc/js/phui/behavior-phui-profile-menu.js' => '12884df9',
     'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
     'rsrc/js/phuix/PHUIXActionView.js' => '8cf6d262',
     'rsrc/js/phuix/PHUIXAutocomplete.js' => '9196fb06',
-    'rsrc/js/phuix/PHUIXDropdownMenu.js' => 'bd4c8dca',
+    'rsrc/js/phuix/PHUIXDropdownMenu.js' => '1622a72d',
     'rsrc/js/phuix/PHUIXFormControl.js' => 'e15869a8',
     'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b',
   ),
@@ -668,7 +668,7 @@
     'javelin-behavior-phabricator-watch-anchor' => '9f36c42d',
     'javelin-behavior-pholio-mock-edit' => 'bee502c8',
     'javelin-behavior-pholio-mock-view' => 'fbe497e7',
-    'javelin-behavior-phui-dropdown-menu' => '54733475',
+    'javelin-behavior-phui-dropdown-menu' => '3d948804',
     'javelin-behavior-phui-file-upload' => 'b003d4fb',
     'javelin-behavior-phui-hovercards' => 'bcaccd64',
     'javelin-behavior-phui-object-box-tabs' => '2bfa2836',
@@ -706,7 +706,7 @@
     'javelin-color' => '7e41274a',
     'javelin-cookie' => '62dfea03',
     'javelin-diffusion-locate-file-source' => 'b42eddc7',
-    'javelin-dom' => '805b806a',
+    'javelin-dom' => '5e5acdda',
     'javelin-dynval' => 'f6555212',
     'javelin-event' => '2ee659ce',
     'javelin-fx' => '54b612ba',
@@ -769,7 +769,7 @@
     'phabricator-core-css' => 'd0801452',
     'phabricator-countdown-css' => '16c52f5c',
     'phabricator-dashboard-css' => 'bc6f2127',
-    'phabricator-drag-and-drop-file-upload' => '58dea2fa',
+    'phabricator-drag-and-drop-file-upload' => 'd1d13c52',
     'phabricator-draggable-list' => '5a13c79f',
     'phabricator-fatal-config-template-css' => '8e6c6fcd',
     'phabricator-feed-css' => 'ecd4ec57',
@@ -821,7 +821,7 @@
     'phui-badge-view-css' => '3baef8db',
     'phui-big-info-view-css' => 'bd903741',
     'phui-box-css' => '5c8387cf',
-    'phui-button-css' => 'a64a8de6',
+    'phui-button-css' => '287efbfa',
     'phui-calendar-css' => 'ccabe893',
     'phui-calendar-day-css' => 'd1cf6f93',
     'phui-calendar-list-css' => '56e6381a',
@@ -869,7 +869,7 @@
     'phuix-action-list-view' => 'b5c256b8',
     'phuix-action-view' => '8cf6d262',
     'phuix-autocomplete' => '9196fb06',
-    'phuix-dropdown-menu' => 'bd4c8dca',
+    'phuix-dropdown-menu' => '1622a72d',
     'phuix-form-control-view' => 'e15869a8',
     'phuix-icon-view' => 'bff6884b',
     'policy-css' => '957ea14c',
@@ -1034,6 +1034,13 @@
       'javelin-workflow',
       'javelin-workboard-controller',
     ),
+    '1622a72d' => array(
+      'javelin-install',
+      'javelin-util',
+      'javelin-dom',
+      'javelin-vector',
+      'javelin-stratcom',
+    ),
     '1ad0a787' => array(
       'javelin-install',
       'javelin-reactor',
@@ -1143,6 +1150,12 @@
       'javelin-util',
       'javelin-uri',
     ),
+    '3d948804' => array(
+      'javelin-behavior',
+      'javelin-stratcom',
+      'javelin-dom',
+      'phuix-dropdown-menu',
+    ),
     '3f5d6dbf' => array(
       'javelin-behavior',
       'javelin-dom',
@@ -1274,12 +1287,6 @@
       'javelin-leader',
       'javelin-json',
     ),
-    54733475 => array(
-      'javelin-behavior',
-      'javelin-stratcom',
-      'javelin-dom',
-      'phuix-dropdown-menu',
-    ),
     '54b612ba' => array(
       'javelin-color',
       'javelin-install',
@@ -1324,14 +1331,6 @@
       'javelin-request',
       'javelin-util',
     ),
-    '58dea2fa' => array(
-      'javelin-install',
-      'javelin-util',
-      'javelin-request',
-      'javelin-dom',
-      'javelin-uri',
-      'phabricator-file-upload',
-    ),
     '59a7976a' => array(
       'javelin-install',
       'javelin-dom',
@@ -1361,6 +1360,13 @@
       'javelin-stratcom',
       'javelin-dom',
     ),
+    '5e5acdda' => array(
+      'javelin-magical-init',
+      'javelin-install',
+      'javelin-util',
+      'javelin-vector',
+      'javelin-stratcom',
+    ),
     '5e9f347c' => array(
       'javelin-behavior',
       'multirow-row-manager',
@@ -1521,13 +1527,6 @@
       'javelin-behavior',
       'javelin-history',
     ),
-    '805b806a' => array(
-      'javelin-magical-init',
-      'javelin-install',
-      'javelin-util',
-      'javelin-vector',
-      'javelin-stratcom',
-    ),
     '834a1173' => array(
       'javelin-behavior',
       'javelin-scrollbar',
@@ -1845,13 +1844,6 @@
       'javelin-vector',
       'phui-hovercard',
     ),
-    'bd4c8dca' => array(
-      'javelin-install',
-      'javelin-util',
-      'javelin-dom',
-      'javelin-vector',
-      'javelin-stratcom',
-    ),
     'bdaf4d04' => array(
       'javelin-behavior',
       'javelin-dom',
@@ -1961,6 +1953,14 @@
       'javelin-dynval',
       'javelin-reactor-dom',
     ),
+    'd1d13c52' => array(
+      'javelin-install',
+      'javelin-util',
+      'javelin-request',
+      'javelin-dom',
+      'javelin-uri',
+      'phabricator-file-upload',
+    ),
     'd254d646' => array(
       'javelin-util',
     ),
diff --git a/src/applications/maniphest/controller/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/ManiphestTaskDetailController.php
--- a/src/applications/maniphest/controller/ManiphestTaskDetailController.php
+++ b/src/applications/maniphest/controller/ManiphestTaskDetailController.php
@@ -166,15 +166,6 @@
         ->setDisabled(!$can_edit)
         ->setWorkflow(!$can_edit));
 
-    $curtain->addAction(
-      id(new PhabricatorActionView())
-        ->setName(pht('Merge Duplicates In'))
-        ->setHref("/search/attach/{$phid}/TASK/merge/")
-        ->setWorkflow(true)
-        ->setIcon('fa-compress')
-        ->setDisabled(!$can_edit)
-        ->setWorkflow(true));
-
     $edit_config = $edit_engine->loadDefaultEditConfiguration();
     $can_create = (bool)$edit_config;
 
@@ -195,7 +186,10 @@
       $edit_uri = $this->getApplicationURI($edit_uri);
     }
 
-    $curtain->addAction(
+    $task_menu = id(new PhabricatorActionListView())
+      ->setUser($viewer);
+
+    $task_menu->addAction(
       id(new PhabricatorActionView())
         ->setName(pht('Create Subtask'))
         ->setHref($edit_uri)
@@ -203,7 +197,7 @@
         ->setDisabled(!$can_create)
         ->setWorkflow(!$can_create));
 
-    $curtain->addAction(
+    $task_menu->addAction(
       id(new PhabricatorActionView())
         ->setName(pht('Edit Blocking Tasks'))
         ->setHref("/search/attach/{$phid}/TASK/blocks/")
@@ -212,6 +206,20 @@
         ->setDisabled(!$can_edit)
         ->setWorkflow(true));
 
+    $task_menu->addAction(
+      id(new PhabricatorActionView())
+        ->setName(pht('Merge Duplicates In'))
+        ->setHref("/search/attach/{$phid}/TASK/merge/")
+        ->setWorkflow(true)
+        ->setIcon('fa-compress')
+        ->setDisabled(!$can_edit)
+        ->setWorkflow(true));
+
+    $curtain->addAction(
+      id(new PhabricatorActionView())
+        ->setName(pht('Edit Related Tasks...'))
+        ->setIcon('fa-anchor')
+        ->setDropdownMenu($task_menu));
 
     $owner_phid = $task->getOwnerPHID();
     $author_phid = $task->getAuthorPHID();
diff --git a/src/view/layout/PhabricatorActionView.php b/src/view/layout/PhabricatorActionView.php
--- a/src/view/layout/PhabricatorActionView.php
+++ b/src/view/layout/PhabricatorActionView.php
@@ -14,6 +14,7 @@
   private $metadata;
   private $selected;
   private $openInNewWindow;
+  private $isDropdown;
 
   public function setSelected($selected) {
     $this->selected = $selected;
@@ -95,6 +96,24 @@
     return $this->openInNewWindow;
   }
 
+  public function setDropdownMenu(PhabricatorActionListView $actions) {
+    Javelin::initBehavior('phui-dropdown-menu');
+
+    $this->addSigil('phui-dropdown-menu');
+    $this->setMetadata(
+      array(
+        'width' => 'auto',
+      ) + $actions->getDropdownMenuMetadata());
+
+    if (!$this->getHref()) {
+      $this->setHref('#');
+    }
+
+    $this->isDropdown = true;
+
+    return $this;
+  }
+
   public function render() {
 
     $icon = null;
@@ -155,6 +174,12 @@
           $target = null;
         }
 
+        if ($this->isDropdown) {
+          $caret = phutil_tag('span', array('class' => 'caret'), '');
+        } else {
+          $caret = null;
+        }
+
         $item = javelin_tag(
           'a',
           array(
@@ -164,7 +189,7 @@
             'sigil' => $sigils,
             'meta' => $this->metadata,
           ),
-          array($icon, $this->name));
+          array($icon, $this->name, $caret));
       }
     } else {
       $item = phutil_tag(
diff --git a/src/view/phui/PHUITimelineEventView.php b/src/view/phui/PHUITimelineEventView.php
--- a/src/view/phui/PHUITimelineEventView.php
+++ b/src/view/phui/PHUITimelineEventView.php
@@ -327,9 +327,7 @@
           'sigil' => $sigil,
           'aria-haspopup' => 'true',
           'aria-expanded' => 'false',
-          'meta' => array(
-            'items' => hsprintf('%s', $action_list),
-          ),
+          'meta' => $action_list->getDropdownMenuMetadata(),
         ),
         array(
           $aural,
diff --git a/webroot/rsrc/css/phui/phui-button.css b/webroot/rsrc/css/phui/phui-button.css
--- a/webroot/rsrc/css/phui/phui-button.css
+++ b/webroot/rsrc/css/phui/phui-button.css
@@ -199,6 +199,7 @@
   border: 1px solid {$blueborder};
   border-radius: 3px;
   margin-bottom: 16px;
+  box-sizing: border-box;
 }
 
 .phuix-dropdown-menu a:focus {
@@ -256,6 +257,20 @@
   margin-left: 6px;
 }
 
+.phabricator-action-view-item .caret {
+  float: right;
+  margin-top: 7px;
+  margin-right: 6px;
+  border-top-color: {$greytext};
+}
+
+a.phabricator-action-view-item.phuix-dropdown-open,
+.device-desktop
+  .phabricator-action-view:hover
+  a.phabricator-action-view-item.phuix-dropdown-open {
+  background: {$darkgreybackground};
+}
+
 .small.dropdown .caret {
   margin-top: 6px;
 }
diff --git a/webroot/rsrc/externals/javelin/lib/DOM.js b/webroot/rsrc/externals/javelin/lib/DOM.js
--- a/webroot/rsrc/externals/javelin/lib/DOM.js
+++ b/webroot/rsrc/externals/javelin/lib/DOM.js
@@ -1011,6 +1011,25 @@
       }
     },
 
+
+    /**
+     * Test if a node is a container for a child.
+     *
+     * @param Node Container node.
+     * @param Node Child node.
+     * @return bool True if the child exists inside the container.
+     */
+    contains: function(container, child) {
+      do {
+        if (child === container) {
+          return true;
+        }
+        child = child.parentNode;
+      } while (child);
+
+      return false;
+    },
+
     _getAutoID : function(node) {
       if (!node.getAttribute('data-autoid')) {
         node.setAttribute('data-autoid', 'autoid_'+(++JX.DOM._autoid));
diff --git a/webroot/rsrc/js/core/DragAndDropFileUpload.js b/webroot/rsrc/js/core/DragAndDropFileUpload.js
--- a/webroot/rsrc/js/core/DragAndDropFileUpload.js
+++ b/webroot/rsrc/js/core/DragAndDropFileUpload.js
@@ -73,19 +73,6 @@
     },
 
     start : function() {
-
-      // TODO: move this to JX.DOM.contains()?
-      function contains(container, child) {
-        do {
-          if (child === container) {
-            return true;
-          }
-          child = child.parentNode;
-        } while (child);
-
-        return false;
-      }
-
       // Firefox has some issues sometimes; implement this click handler so
       // the user can recover. See T5188.
       var on_click = JX.bind(this, function (e) {
@@ -115,7 +102,7 @@
           }
         }
 
-        if (contains(this._getTarget(), e.getTarget())) {
+        if (JX.DOM.contains(this._getTarget(), e.getTarget())) {
           this._updateDepth(1);
         }
 
@@ -130,7 +117,7 @@
           return;
         }
 
-        if (contains(this._getTarget(), e.getTarget())) {
+        if (JX.DOM.contains(this._getTarget(), e.getTarget())) {
           this._updateDepth(-1);
         }
       });
diff --git a/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js b/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js
--- a/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js
+++ b/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js
@@ -21,6 +21,7 @@
     var icon = e.getNode('phui-dropdown-menu');
     data.menu = new JX.PHUIXDropdownMenu(icon);
     data.menu.setContent(list);
+    data.menu.setWidth(data.width || null);
     data.menu.open();
 
     JX.DOM.listen(list, 'click', 'tag:a', function(e) {
diff --git a/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js b/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js
--- a/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js
+++ b/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js
@@ -51,6 +51,11 @@
     offsetY: 0
   },
 
+  statics: {
+    _lastDim: null,
+    _lastPos: null
+  },
+
   members: {
     _node: null,
     _menu: null,
@@ -80,6 +85,13 @@
       if (!this._open) {
         return;
       }
+
+      // Save this menu's position and dimensions as the last closed menu.
+      // We'll reuse them if we're opening a submenu.
+      var self = JX.PHUIXDropdownMenu;
+      self._lastPos = JX.$V(this._menu);
+      self._lastDim = JX.Vector.getDim(this._menu);
+
       this._open = false;
       this._hide();
 
@@ -120,11 +132,8 @@
       }
 
       var t = e.getTarget();
-      while (t) {
-        if (t == this._menu || t == this._node) {
-          return;
-        }
-        t = t.parentNode;
+      if (JX.DOM.contains(this._menu, t) || JX.DOM.contains(this._node, t)) {
+        return;
       }
 
       this.close();
@@ -133,7 +142,14 @@
     _show : function() {
       document.body.appendChild(this._menu);
 
-      if (this.getWidth()) {
+      var width = this.getWidth();
+      if (width == 'auto') {
+        if (JX.DOM.contains(document, this._node)) {
+          var d = new JX.Vector.getDim(this._node);
+          d.y = null;
+          d.setDim(this._menu);
+        }
+      } else if (width) {
         new JX.Vector(this.getWidth(), null).setDim(this._menu);
       }
 
@@ -168,6 +184,18 @@
       var v = JX.$V(this._node);
       var d = JX.Vector.getDim(this._node);
 
+      // If the node has been removed from the DOM, assume we are opening
+      // a new dropdown from an existing dropdown. We're just going to replace
+      // the old dropdown.
+      if (!JX.DOM.contains(document, this._node)) {
+        var self = JX.PHUIXDropdownMenu;
+        if (self._lastPos) {
+          v = self._lastPos;
+          d = self._lastDim;
+          d.y = 0;
+        }
+      }
+
       switch (this.getAlign()) {
         case 'right':
           v = v.add(d)