diff --git a/externals/JsShrink/jsShrink.php b/externals/JsShrink/jsShrink.php
--- a/externals/JsShrink/jsShrink.php
+++ b/externals/JsShrink/jsShrink.php
@@ -35,7 +35,7 @@
 	list(, $context, $regexp, $result, $word, $operator) = $match;
 	if ($word != '') {
 		$result = ($last == 'word' ? "\n" : ($last == 'return' ? " " : "")) . $result;
-		$last = ($word == 'return' || $word == 'throw' || $word == 'break' ? 'return' : 'word');
+		$last = ($word == 'return' || $word == 'throw' || $word == 'break' || $word == 'async' ? 'return' : 'word');
 	} elseif ($operator) {
 		$result = ($last == $operator[0] ? "\n" : "") . $result;
 		$last = $operator[0];
diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -14,7 +14,7 @@
     'dark-console.pkg.js' => '187792c2',
     'differential.pkg.css' => '6d3700f0',
     'differential.pkg.js' => '46fcb3af',
-    'diffusion.pkg.css' => '42c75c37',
+    'diffusion.pkg.css' => '354279ea',
     'diffusion.pkg.js' => '78c9885d',
     'maniphest.pkg.css' => '35995d6d',
     'maniphest.pkg.js' => 'c9308721',
@@ -69,7 +69,7 @@
     'rsrc/css/application/differential/revision-history.css' => '237a2979',
     'rsrc/css/application/differential/revision-list.css' => '93d2df7d',
     'rsrc/css/application/differential/table-of-contents.css' => 'bba788b9',
-    'rsrc/css/application/diffusion/diffusion-icons.css' => '23b31a1b',
+    'rsrc/css/application/diffusion/diffusion-icons.css' => 'e812add2',
     'rsrc/css/application/diffusion/diffusion-readme.css' => 'b68a76e4',
     'rsrc/css/application/diffusion/diffusion-repository.css' => 'b89e8c6c',
     'rsrc/css/application/diffusion/diffusion.css' => 'e46232d6',
@@ -470,7 +470,7 @@
     'rsrc/js/core/behavior-badge-view.js' => '92cdd7b6',
     'rsrc/js/core/behavior-bulk-editor.js' => 'aa6d2308',
     'rsrc/js/core/behavior-choose-control.js' => '04f8a1e3',
-    'rsrc/js/core/behavior-copy.js' => 'cf32921f',
+    'rsrc/js/core/behavior-copy.js' => '96b63a02',
     'rsrc/js/core/behavior-detect-timezone.js' => '78bc5d94',
     'rsrc/js/core/behavior-device.js' => 'ac2b1e01',
     'rsrc/js/core/behavior-drag-and-drop-textarea.js' => '6bc7ccf7',
@@ -499,7 +499,7 @@
     'rsrc/js/core/behavior-reveal-content.js' => 'b105a3a6',
     'rsrc/js/core/behavior-scrollbar.js' => '92388bae',
     'rsrc/js/core/behavior-search-typeahead.js' => '1cb7d027',
-    'rsrc/js/core/behavior-select-content.js' => 'e8240b50',
+    'rsrc/js/core/behavior-select-content.js' => 'c538cbfc',
     'rsrc/js/core/behavior-select-on-click.js' => '66365ee2',
     'rsrc/js/core/behavior-setup-check-https.js' => '01384686',
     'rsrc/js/core/behavior-time-typeahead.js' => '5803b9e7',
@@ -567,7 +567,7 @@
     'differential-revision-list-css' => '93d2df7d',
     'differential-table-of-contents-css' => 'bba788b9',
     'diffusion-css' => 'e46232d6',
-    'diffusion-icons-css' => '23b31a1b',
+    'diffusion-icons-css' => 'e812add2',
     'diffusion-readme-css' => 'b68a76e4',
     'diffusion-repository-css' => 'b89e8c6c',
     'diviner-shared-css' => '4bd263b0',
@@ -644,7 +644,7 @@
     'javelin-behavior-owners-path-editor' => 'ff688a7a',
     'javelin-behavior-passphrase-credential-control' => '48fe33d0',
     'javelin-behavior-phabricator-autofocus' => '65bb0011',
-    'javelin-behavior-phabricator-clipboard-copy' => 'cf32921f',
+    'javelin-behavior-phabricator-clipboard-copy' => '96b63a02',
     'javelin-behavior-phabricator-gesture' => 'b58d1a2a',
     'javelin-behavior-phabricator-gesture-example' => '242dedd0',
     'javelin-behavior-phabricator-keyboard-pager' => '1325b731',
@@ -687,7 +687,7 @@
     'javelin-behavior-repository-crossreference' => '44d48cd1',
     'javelin-behavior-scrollbar' => '92388bae',
     'javelin-behavior-search-reorder-queries' => 'b86f297f',
-    'javelin-behavior-select-content' => 'e8240b50',
+    'javelin-behavior-select-content' => 'c538cbfc',
     'javelin-behavior-select-on-click' => '66365ee2',
     'javelin-behavior-setup-check-https' => '01384686',
     'javelin-behavior-stripe-payment-form' => '02cb4398',
@@ -1770,6 +1770,12 @@
       'javelin-dom',
       'javelin-router',
     ),
+    '96b63a02' => array(
+      'javelin-behavior',
+      'javelin-dom',
+      'javelin-stratcom',
+      'phabricator-notification',
+    ),
     '98ef467f' => array(
       'javelin-behavior',
       'javelin-dom',
@@ -2022,6 +2028,11 @@
       'javelin-workboard-card',
       'javelin-workboard-header',
     ),
+    'c538cbfc' => array(
+      'javelin-behavior',
+      'javelin-stratcom',
+      'javelin-dom',
+    ),
     'c687e867' => array(
       'javelin-behavior',
       'javelin-dom',
@@ -2063,11 +2074,6 @@
       'phuix-formation-column-view',
       'phuix-formation-flank-view',
     ),
-    'cf32921f' => array(
-      'javelin-behavior',
-      'javelin-dom',
-      'javelin-stratcom',
-    ),
     'd12d214f' => array(
       'javelin-install',
       'javelin-dom',
@@ -2146,11 +2152,6 @@
       'javelin-dom',
       'phabricator-draggable-list',
     ),
-    'e8240b50' => array(
-      'javelin-behavior',
-      'javelin-stratcom',
-      'javelin-dom',
-    ),
     'e9a2940f' => array(
       'javelin-behavior',
       'javelin-request',
diff --git a/src/applications/diffusion/view/DiffusionCloneURIView.php b/src/applications/diffusion/view/DiffusionCloneURIView.php
--- a/src/applications/diffusion/view/DiffusionCloneURIView.php
+++ b/src/applications/diffusion/view/DiffusionCloneURIView.php
@@ -40,6 +40,7 @@
     require_celerity_resource('diffusion-icons-css');
 
     Javelin::initBehavior('select-content');
+    Javelin::initBehavior('phabricator-clipboard-copy');
 
     $uri_id = celerity_generate_unique_node_id();
 
@@ -53,6 +54,11 @@
         'value' => $display,
         'class' => 'diffusion-clone-uri',
         'readonly' => 'true',
+        'sigil' => 'select-content',
+        'meta' => array(
+          'selectID' => $uri_id,
+          'once' => true,
+        ),
       ));
 
     $uri = $this->getRepositoryURI();
@@ -71,17 +77,30 @@
         break;
     }
 
-    $io = id(new PHUIButtonView())
+    $io = javelin_tag(
+      'span',
+      array(
+        'class' => 'diffusion-clone-uri-io',
+        'sigil' => 'has-tooltip',
+        'meta' => array(
+          'tip' => $io_tip,
+        ),
+      ),
+      id(new PHUIIconView())->setIcon($io_icon));
+
+    $copy = id(new PHUIButtonView())
       ->setTag('a')
       ->setColor(PHUIButtonView::GREY)
-      ->setIcon($io_icon)
+      ->setIcon('fa-clipboard')
       ->setHref('#')
-      ->addSigil('select-content')
+      ->addSigil('clipboard-copy')
       ->addSigil('has-tooltip')
       ->setMetadata(
         array(
-          'tip' => $io_tip,
-          'selectID' => $uri_id,
+          'tip' => pht('Copy repository URI'),
+          'text' => $display,
+          'successMessage' => pht('Repository URI copied.'),
+          'errorMessage' => pht('Copy of Repository URI failed.'),
         ));
 
     switch ($uri->getEffectiveIOType()) {
@@ -121,19 +140,18 @@
       ->setHref($auth_uri)
       ->setDisabled($auth_disabled);
 
-    $cells = array();
-    $cells[] = phutil_tag('td', array(), $input);
-    $cells[] = phutil_tag('th', array(), $io);
-    $cells[] = phutil_tag('th', array(), $credentials);
-
-    $row = phutil_tag('tr', array(), $cells);
+    $elements = array();
+    $elements[] = $io;
+    $elements[] = $input;
+    $elements[] = $copy;
+    $elements[] = $credentials;
 
     return phutil_tag(
-      'table',
+      'div',
       array(
-        'class' => 'diffusion-clone-uri-table',
+        'class' => 'diffusion-clone-uri-wrapper',
       ),
-      $row);
+      $elements);
   }
 
 }
diff --git a/src/applications/uiexample/examples/PHUIButtonExample.php b/src/applications/uiexample/examples/PHUIButtonExample.php
--- a/src/applications/uiexample/examples/PHUIButtonExample.php
+++ b/src/applications/uiexample/examples/PHUIButtonExample.php
@@ -115,6 +115,8 @@
         $button->setMetadata(
           array(
             'text' => $copy,
+            'successMessage' => pht('Text copied into clipboard.'),
+            'errorMessage' => pht('Failed to copy text into clipboard.'),
           ));
       }
 
diff --git a/webroot/rsrc/css/application/diffusion/diffusion-icons.css b/webroot/rsrc/css/application/diffusion/diffusion-icons.css
--- a/webroot/rsrc/css/application/diffusion/diffusion-icons.css
+++ b/webroot/rsrc/css/application/diffusion/diffusion-icons.css
@@ -2,11 +2,6 @@
  * @provides diffusion-icons-css
  */
 
-input.diffusion-clone-uri {
-  display: block;
-  width: 100%;
-}
-
 .diffusion-clone-extras {
   font-size: 11px;
   text-align: right;
@@ -35,21 +30,35 @@
   padding: 0;
 }
 
-.diffusion-clone-uri-table {
-  width: 100%;
+.diffusion-clone-uri-wrapper {
+  display: flex;
 }
 
-.diffusion-clone-uri-table th {
-  width: 24px;
-  padding: 0 0 0 4px;
+.diffusion-clone-uri-wrapper .diffusion-clone-uri-io {
+  align-items: center;
+  justify-content: center;
+  border: 1px solid {$greyborder};
+  border-top-left-radius: 3px;
+  border-bottom-left-radius: 3px;
+  display: flex;
+  width: 38px;
 }
 
-.diffusion-clone-uri-table th a.button {
+.diffusion-clone-uri-wrapper a.button {
   width: 12px;
   height: 19px;
+  margin-left: 4px;
 }
 
-.diffusion-clone-uri-table th a.button .phui-icon-view {
+.diffusion-clone-uri-wrapper a.button .phui-icon-view {
   left: 15px;
   top: 7px;
 }
+
+.diffusion-clone-uri-wrapper  input.diffusion-clone-uri {
+  border-left: none;
+  border-top-left-radius: 0px;
+  border-bottom-left-radius: 0px;
+  display: block;
+  width: 100%;
+}
diff --git a/webroot/rsrc/js/core/behavior-copy.js b/webroot/rsrc/js/core/behavior-copy.js
--- a/webroot/rsrc/js/core/behavior-copy.js
+++ b/webroot/rsrc/js/core/behavior-copy.js
@@ -3,41 +3,81 @@
  * @requires javelin-behavior
  *           javelin-dom
  *           javelin-stratcom
+ *           phabricator-notification
  * @javelin
  */
 
 JX.behavior('phabricator-clipboard-copy', function() {
 
-  if (!document.queryCommandSupported) {
-    return;
-  }
+  var fallback_working = document.queryCommandSupported &&
+    document.queryCommandSupported('copy');
 
-  if (!document.queryCommandSupported('copy')) {
+  if (!navigator.clipboard && !fallback_working) {
     return;
   }
 
   JX.DOM.alterClass(document.body, 'supports-clipboard', true);
 
-  JX.Stratcom.listen('click', 'clipboard-copy', function(e) {
-    e.kill();
-
-    var data = e.getNodeData('clipboard-copy');
+  var copy_fallback = function(text) {
     var attr = {
-      value: data.text || '',
+      value: text || '',
       className: 'clipboard-buffer'
     };
 
     var node = JX.$N('textarea', attr);
     document.body.appendChild(node);
 
-    try {
-      node.select();
-      document.execCommand('copy');
-    } catch (ignored) {
-      // Ignore any errors we hit.
+    node.select();
+    document.execCommand('copy');
+
+    JX.DOM.remove(node);
+  };
+
+  var show_success_message = function(message) {
+    if (!message) {
+      return;
     }
+    new JX.Notification()
+      .setContent(message)
+      .alterClassName('jx-notification-done', true)
+      .setDuration(8000)
+      .show();
+  };
 
-   JX.DOM.remove(node);
+  var show_error_message = function(message) {
+    if (!message) {
+      return;
+    }
+    new JX.Notification()
+      .setContent(message)
+      .alterClassName('jx-notification-error', true)
+      .setDuration(8000)
+      .show();
+  };
+
+  JX.Stratcom.listen('click', 'clipboard-copy', function(e) {
+    var data = e.getNodeData('clipboard-copy');
+    var text = data.text || '';
+
+    var copy = async function( // jshint ignore:line
+      text,
+      successMessage,
+      errorMessage
+    ) {
+      try {
+        if (navigator.clipboard) {
+          await navigator.clipboard.writeText(text);
+        } else {
+          copy_fallback(text);
+        }
+        show_success_message(successMessage);
+      } catch (ex) {
+        show_error_message(errorMessage);
+      }
+    };
+
+    e.kill();
+    copy(text, data.successMessage, data.errorMessage);
   });
 
 });
diff --git a/webroot/rsrc/js/core/behavior-select-content.js b/webroot/rsrc/js/core/behavior-select-content.js
--- a/webroot/rsrc/js/core/behavior-select-content.js
+++ b/webroot/rsrc/js/core/behavior-select-content.js
@@ -16,8 +16,16 @@
       var node = e.getNode('select-content');
       var data = JX.Stratcom.getData(node);
 
+      if (data.once && data.selected) {
+        return;
+      }
+
       var target = JX.$(data.selectID);
       JX.DOM.focus(target);
       target.select();
+
+      if (data.once) {
+        JX.Stratcom.addData(node, {selected: true});
+      }
     });
 });