diff --git a/core/modules/block/block.links.action.yml b/core/modules/block/block.links.action.yml
new file mode 100644
index 0000000..bbdfb27
--- /dev/null
+++ b/core/modules/block/block.links.action.yml
@@ -0,0 +1,7 @@
+block_layout_add_action:
+  route_name: block.admin_layout_add
+  title: 'Add block to layout'
+  appears_on:
+    - block.admin_display
+    - block.admin_display_theme
+  class: \Drupal\block\Plugin\Menu\LocalAction\BlockLayoutAddLocalAction
diff --git a/core/modules/block/block.routing.yml b/core/modules/block/block.routing.yml
index 2f26a38..37de404 100644
--- a/core/modules/block/block.routing.yml
+++ b/core/modules/block/block.routing.yml
@@ -42,6 +42,15 @@ block.admin_display_theme:
     _access_theme: 'TRUE'
     _permission: 'administer blocks'
 
+block.admin_layout_add:
+  path: 'admin/structure/block/list/{theme}/add'
+  defaults:
+    _controller: '\Drupal\block\Controller\BlockListController::layout'
+    _title: 'Add block to layout'
+  requirements:
+    _access_theme: 'TRUE'
+    _permission: 'administer blocks'
+
 block.admin_add:
   path: '/admin/structure/block/add/{plugin_id}/{theme}'
   defaults:
diff --git a/core/modules/block/css/block.admin.css b/core/modules/block/css/block.admin.css
index d9f32a2..3354afe 100644
--- a/core/modules/block/css/block.admin.css
+++ b/core/modules/block/css/block.admin.css
@@ -1,3 +1,4 @@
+/* Block demo mode */
 .block-region {
   background-color: #ff6;
   margin-top: 4px;
@@ -21,88 +22,10 @@ a.block-demo-backlink:visited {
 a.block-demo-backlink:hover {
   text-decoration: underline;
 }
-
-.layout-region {
-  box-sizing: border-box;
-}
-.block-list-secondary {
-  border: 1px solid #bfbfbf;
-  border-bottom-width: 0;
-}
-.block-list {
-  padding: 0 0.75em;
-  margin: 0;
-}
-.block-list li {
-  list-style: none;
-  padding: 0.1em 0;
-}
-.block-list a:before {
-  content: '+ ';
-}
-.block-list-secondary .form-type-search {
-  padding: 0 1em;
-}
+/* Configure block form - Block description */
 .block-form .form-item-settings-admin-label label {
   display: inline;
 }
 .block-form .form-item-settings-admin-label label:after {
   content: ':';
-}
-
-/* Wide screens */
-@media
-screen and (min-width: 780px),
-(orientation: landscape) and (min-device-height: 780px) {
-
-  .block-list-primary {
-    float: left; /* LTR */
-    width: 75%;
-    padding-right: 2em;
-  }
-  [dir="rtl"] .block-list-primary {
-    float: right;
-    padding-left: 2em;
-    padding-right: 0;
-  }
-
-  .block-list-secondary {
-    float: right; /* LTR */
-    width: 25%;
-  }
-  [dir="rtl"] .block-list-secondary {
-    float: left;
-  }
-
-  /* @todo File an issue to add a standard class to all text-like inputs */
-  .block-list-secondary .form-autocomplete,
-  .block-list-secondary .form-text,
-  .block-list-secondary .form-tel,
-  .block-list-secondary .form-email,
-  .block-list-secondary .form-url,
-  .block-list-secondary .form-search,
-  .block-list-secondary .form-number,
-  .block-list-secondary .form-color,
-  .block-list-secondary textarea {
-    box-sizing:         border-box;
-    width: 100%;
-    max-width: 100%;
-  }
-}
-
-/**
- * The vertical toolbar mode gets triggered for narrow screens, which throws off
- * the intent of media queries written for the viewport width. When the vertical
- * toolbar is on, we need to suppress layout for the original media width + the
- * toolbar width (240px). In this case, 240px + 780px.
- */
-@media
-screen and (max-width: 1020px) {
-
-  .toolbar-vertical.toolbar-tray-open .block-list-primary,
-  .toolbar-vertical.toolbar-tray-open .block-list-secondary {
-    float: none;
-    width: auto;
-    padding-right: 0;
-  }
-}
+}
\ No newline at end of file
diff --git a/core/modules/block/js/block.admin.js b/core/modules/block/js/block.admin.js
index 23109f4..79a522f 100644
--- a/core/modules/block/js/block.admin.js
+++ b/core/modules/block/js/block.admin.js
@@ -19,26 +19,9 @@
   Drupal.behaviors.blockFilterByText = {
     attach: function (context, settings) {
       var $input = $('input.block-filter-text').once('block-filter-text');
-      var $element = $($input.attr('data-element'));
-      var $blocks;
-      var $details;
+      var $table = $($input.attr('data-element'));;
+      var $filter_rows;
 
-      /**
-       * Hides the `<details>` element for a category if it has no visible blocks.
-       *
-       * @param {number} index
-       * @param {HTMLElement} element
-       */
-      function hideCategoryDetails(index, element) {
-        var $catDetails = $(element);
-        $catDetails.toggle($catDetails.find('li:visible').length > 0);
-      }
-
-      /**
-       * Filters the block list.
-       *
-       * @param {jQuery.Event} e
-       */
       function filterBlockList(e) {
         var query = $(e.target).val().toLowerCase();
 
@@ -46,39 +29,28 @@
          * Shows or hides the block entry based on the query.
          *
          * @param {number} index
-         * @param {HTMLElement} block
+         * @param {HTMLElement} label
          */
-        function showBlockEntry(index, block) {
-          var $block = $(block);
-          var $sources = $block.find('.block-filter-text-source');
-          var textMatch = $sources.text().toLowerCase().indexOf(query) !== -1;
-          $block.toggle(textMatch);
+        function showBlockEntry(index, label) {
+          var $label = $(label);
+          var $row = $label.parent().parent();
+          var textMatch = $label.text().toLowerCase().indexOf(query) !== -1;
+          $row.toggle(textMatch);
         }
 
-        // Filter if the length of the query is at least 2 characters.
+        // Filter if the query is at least 2 characters.
         if (query.length >= 2) {
-          $blocks.each(showBlockEntry);
-
-          // Note that we first open all <details> to be able to use ':visible'.
-          // Mark the <details> elements that were closed before filtering, so
-          // they can be reclosed when filtering is removed.
-          $details.not('[open]').attr('data-drupal-block-state', 'forced-open');
-          // Hide the category <details> if they don't have any visible rows.
-          $details.attr('open', 'open').each(hideCategoryDetails);
+          $filter_rows.each(showBlockEntry);
         }
         else {
-          $blocks.show();
-          $details.show();
-          // Return <details> elements that had been closed before filtering
-          // to a closed state.
-          $details.filter('[data-drupal-block-state="forced-open"]').removeAttr('open data-drupal-block-state');
+          $filter_rows.each(function(index) {
+            $(this).parent().parent().show();
+          });
         }
       }
 
-      if ($element.length) {
-        $details = $element.find('details');
-        $blocks = $details.find('li');
-
+      if ($table.length) {
+        $filter_rows = $table.find('div.block-filter-text-source');
         $input.on('keyup', filterBlockList);
       }
     }
diff --git a/core/modules/block/src/BlockListBuilder.php b/core/modules/block/src/BlockListBuilder.php
index aa669fa..643fcad 100644
--- a/core/modules/block/src/BlockListBuilder.php
+++ b/core/modules/block/src/BlockListBuilder.php
@@ -143,7 +143,6 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       $form['#attached']['drupalSettings']['blockPlacement'] = $placement;
     }
     $entities = $this->load();
-    $form['#theme'] = array('block_list');
     $form['#attached']['library'][] = 'core/drupal.tableheader';
     $form['#attached']['library'][] = 'block/drupal.block';
     $form['#attached']['library'][] = 'block/drupal.block.admin';
@@ -199,7 +198,6 @@ public function buildForm(array $form, FormStateInterface $form_state) {
         'relationship' => 'sibling',
         'group' => 'block-region-select',
         'subgroup' => 'block-region-' . $region,
-        'hidden' => FALSE,
       );
       $form['blocks']['#tabledrag'][] = array(
         'action' => 'order',
@@ -306,69 +304,6 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#button_type' => 'primary',
     );
 
-    $form['place_blocks']['title'] = array(
-      '#type' => 'container',
-      '#markup' => '<h3>' . t('Place blocks') . '</h3>',
-      '#attributes' => array(
-        'class' => array(
-          'entity-meta__header',
-        ),
-      ),
-    );
-
-    $form['place_blocks']['filter'] = array(
-      '#type' => 'search',
-      '#title' => t('Filter'),
-      '#title_display' => 'invisible',
-      '#size' => 30,
-      '#placeholder' => t('Filter by block name'),
-      '#attributes' => array(
-        'class' => array('block-filter-text'),
-        'data-element' => '.entity-meta',
-        'title' => t('Enter a part of the block name to filter by.'),
-      ),
-    );
-
-    $form['place_blocks']['list']['#type'] = 'container';
-    $form['place_blocks']['list']['#attributes']['class'][] = 'entity-meta';
-
-    // Only add blocks which work without any available context.
-    $definitions = $this->blockManager->getDefinitionsForContexts();
-    $sorted_definitions = $this->blockManager->getSortedDefinitions($definitions);
-    foreach ($sorted_definitions as $plugin_id => $plugin_definition) {
-      $category = SafeMarkup::checkPlain($plugin_definition['category']);
-      $category_key = 'category-' . $category;
-      if (!isset($form['place_blocks']['list'][$category_key])) {
-        $form['place_blocks']['list'][$category_key] = array(
-          '#type' => 'details',
-          '#title' => $category,
-          '#open' => TRUE,
-          'content' => array(
-            '#theme' => 'links',
-            '#links' => array(),
-            '#attributes' => array(
-              'class' => array(
-                'block-list',
-              ),
-            ),
-          ),
-        );
-      }
-      $form['place_blocks']['list'][$category_key]['content']['#links'][$plugin_id] = array(
-        'title' => $plugin_definition['admin_label'],
-        'url' => Url::fromRoute('block.admin_add', [
-          'plugin_id' => $plugin_id,
-          'theme' => $this->theme
-        ]),
-        'attributes' => array(
-          'class' => array('use-ajax', 'block-filter-text-source'),
-          'data-dialog-type' => 'modal',
-          'data-dialog-options' => Json::encode(array(
-            'width' => 700,
-          )),
-        ),
-      );
-    }
     return $form;
   }
 
diff --git a/core/modules/block/src/Controller/BlockListController.php b/core/modules/block/src/Controller/BlockListController.php
index 72aa445..8533f8f 100644
--- a/core/modules/block/src/Controller/BlockListController.php
+++ b/core/modules/block/src/Controller/BlockListController.php
@@ -7,7 +7,11 @@
 
 namespace Drupal\block\Controller;
 
+use Drupal\Component\Serialization\Json;
+use Drupal\Core\Block\BlockManagerInterface;
 use Drupal\Core\Entity\Controller\EntityListController;
+use Drupal\Core\Url;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -16,6 +20,32 @@
 class BlockListController extends EntityListController {
 
   /**
+   * The block manager.
+   *
+   * @var \Drupal\Core\Block\BlockManagerInterface
+   */
+  protected $blockManager;
+
+  /**
+   * Constructs a BlockListController object.
+   *
+   * @param \Drupal\Core\Block\BlockManagerInterface $block_manager
+   *   The block manager.
+   */
+  public function __construct(BlockManagerInterface $block_manager) {
+    $this->blockManager = $block_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('plugin.manager.block')
+    );
+  }
+
+  /**
    * Shows the block administration page.
    *
    * @param string|null $theme
@@ -31,4 +61,96 @@ public function listing($theme = NULL, Request $request = NULL) {
     return $this->entityManager()->getListBuilder('block')->render($theme, $request);
   }
 
+  /**
+   * Shows a list of blocks that can be added to a theme's layout.
+   *
+   * @param string $theme
+   *   Theme key of the block list.
+   *
+   * @return array
+   *   A render array as expected by drupal_render().
+   */
+  public function layout($theme) {
+    $headers = [
+      ['data' => $this->t('Block'), 'field' => 'name'],
+      ['data' => $this->t('Category'), 'field' => 'category', 'sort' => 'asc'],
+      ['data' => $this->t('Operations')],
+    ];
+    $rows = [];
+
+    // Only add blocks which work without any available context.
+    $definitions = $this->blockManager->getDefinitionsForContexts();
+    // Do not display the 'broken' plugin in the UI.
+    unset($definitions['broken']);
+
+    $order = tablesort_get_order($headers);
+    $sort = tablesort_get_sort($headers);
+    if ($order['name'] == $this->t('Category')) {
+      // Order by category, and then by label.
+      uasort($definitions, function ($a, $b) use ($sort) {
+        if ($a['category'] != $b['category']) {
+          return strnatcasecmp($a['category'], $b['category']) * ($sort == 'asc' ? 1 : -1);
+        }
+        return strnatcasecmp($a['admin_label'], $b['admin_label']);
+      });
+    }
+    else {
+      // Order by label only.
+      uasort($definitions, function ($a, $b) use ($sort) {
+        return strnatcasecmp($a['admin_label'], $b['admin_label']) * ($sort == 'asc' ? 1 : -1);
+      });
+    }
+
+    foreach ($definitions as $plugin_id => $plugin_definition) {
+      $row = [];
+      $row['title']['data'] = [
+        '#markup' => $plugin_definition['admin_label'],
+        '#prefix' => '<div class="block-filter-text-source">',
+        '#suffix' => '</div>',
+      ];
+      $row['category']['data'] = $plugin_definition['category'];
+      $links['add'] = [
+        'title' => $this->t('Add block'),
+        'url' => Url::fromRoute('block.admin_add', ['plugin_id' => $plugin_id, 'theme' => $theme]),
+        'attributes' => [
+          'class' => ['use-ajax'],
+          'data-dialog-type' => 'modal',
+          'data-dialog-options' => Json::encode(['width' => 700]),
+        ],
+      ];
+      $row['operations']['data'] = [
+        '#type' => 'operations',
+        '#links' => $links,
+      ];
+      $rows[] = $row;
+    }
+
+    $build['#attached']['library'][] = 'block/drupal.block.admin';
+
+    $build['filter'] = array(
+      '#type' => 'search',
+      '#title' => $this->t('Filter'),
+      '#title_display' => 'invisible',
+      '#size' => 30,
+      '#placeholder' => $this->t('Filter by block name'),
+      '#attributes' => [
+        'class' => ['block-filter-text'],
+        'data-element' => '.block-add-table',
+        'title' => $this->t('Enter a part of the block name to filter by.'),
+      ],
+    );
+
+    $build['blocks'] = [
+      '#type' => 'table',
+      '#header' => $headers,
+      '#rows' => $rows,
+      '#empty' => $this->t('No blocks available.'),
+      '#attributes' => [
+        'class' => ['block-add-table'],
+      ],
+    ];
+
+    return $build;
+  }
+
 }
diff --git a/core/modules/block/src/Plugin/Menu/LocalAction/BlockLayoutAddLocalAction.php b/core/modules/block/src/Plugin/Menu/LocalAction/BlockLayoutAddLocalAction.php
new file mode 100644
index 0000000..8c7bd73
--- /dev/null
+++ b/core/modules/block/src/Plugin/Menu/LocalAction/BlockLayoutAddLocalAction.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\Plugin\Menu\LocalAction\BlockLayoutAddLocalAction.
+ */
+
+namespace Drupal\block\Plugin\Menu\LocalAction;
+
+use Drupal\Core\Menu\LocalActionDefault;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Routing\UrlGeneratorTrait;
+
+/**
+ * Modifies the "Add block to layout" action.
+ */
+class BLockLayoutAddLocalAction extends LocalActionDefault {
+
+  use UrlGeneratorTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRouteParameters(RouteMatchInterface $route_match) {
+    $route = $this->routeProvider->getRouteByName($this->getRouteName());
+
+    // The default task is always the default theme since it is given a lower
+    // weight. Therefore, it should always be the default action target.
+    $theme = \Drupal::config('system.theme')->get('default');
+    // The action target requires a {theme} parameter, but that parameter is
+    // not set in the default task route, so it has to be manually provided.
+    $route->setDefault('theme', $theme);
+
+    return parent::getRouteParameters($route_match);
+  }
+
+}
diff --git a/core/modules/block/src/Tests/BlockLanguageCacheTest.php b/core/modules/block/src/Tests/BlockLanguageCacheTest.php
index 45f6803..77a9e9d 100644
--- a/core/modules/block/src/Tests/BlockLanguageCacheTest.php
+++ b/core/modules/block/src/Tests/BlockLanguageCacheTest.php
@@ -61,7 +61,7 @@ public function testBlockLinks() {
 
     // Create the block cache for all languages.
     foreach ($this->langcodes as $langcode) {
-      $this->drupalGet('admin/structure/block', array('language' => $langcode));
+      $this->drupalGet('admin/structure/block/list/classy/add', array('language' => $langcode));
     }
 
     // Create a menu in the default language.
@@ -72,7 +72,7 @@ public function testBlockLinks() {
 
     // Check that the block is listed for all languages.
     foreach ($this->langcodes as $langcode) {
-      $this->drupalGet('admin/structure/block', array('language' => $langcode));
+      $this->drupalGet("admin/structure/block/list/classy/add", array('language' => $langcode));
       $this->assertText($edit['label']);
     }
   }
diff --git a/core/modules/block/src/Tests/BlockUiTest.php b/core/modules/block/src/Tests/BlockUiTest.php
index aba4ba1..254f5bd 100644
--- a/core/modules/block/src/Tests/BlockUiTest.php
+++ b/core/modules/block/src/Tests/BlockUiTest.php
@@ -91,7 +91,7 @@ public function testBlockDemoUiPage() {
   /**
    * Test block admin page exists and functions correctly.
    */
-  function testBlockAdminUiPage() {
+  public function testBlockAdminUiPage() {
     // Visit the blocks admin ui.
     $this->drupalGet('admin/structure/block');
     // Look for the blocks table.
@@ -132,23 +132,25 @@ function testBlockAdminUiPage() {
    * Tests the block categories on the listing page.
    */
   public function testCandidateBlockList() {
+    $pattern = '//tr[.//td/div[text()=:title] and .//td[text()=:category]]';
     $arguments = array(
-      ':ul_class' => 'block-list',
-      ':li_class' => 'test-block-instantiation',
-      ':href' => 'admin/structure/block/add/test_block_instantiation/classy',
-      ':text' => 'Display message',
+      ':title' => 'Display message',
+      ':category' => 'Block test',
     );
 
-    $this->drupalGet('admin/structure/block');
-    $elements = $this->xpath('//details[@id="edit-category-block-test"]//ul[contains(@class, :ul_class)]/li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments);
+    // Check if the block is listed.
+    $this->drupalGet('admin/structure/block/list/classy/add');
+    $elements = $this->xpath($pattern, $arguments);
     $this->assertTrue(!empty($elements), 'The test block appears in the category for its module.');
 
     // Trigger the custom category addition in block_test_block_alter().
     $this->container->get('state')->set('block_test_info_alter', TRUE);
     $this->container->get('plugin.manager.block')->clearCachedDefinitions();
 
-    $this->drupalGet('admin/structure/block');
-    $elements = $this->xpath('//details[@id="edit-category-custom-category"]//ul[contains(@class, :ul_class)]/li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments);
+    // Check if the block is listed with a custom category.
+    $this->drupalGet('admin/structure/block/list/classy/add');
+    $arguments[':category'] = "Custom category";
+    $elements = $this->xpath($pattern, $arguments);
     $this->assertTrue(!empty($elements), 'The test block appears in a custom category controlled by block_test_block_alter().');
   }
 
diff --git a/core/modules/block/src/Tests/BlockXssTest.php b/core/modules/block/src/Tests/BlockXssTest.php
index f24811a..4e4c560 100644
--- a/core/modules/block/src/Tests/BlockXssTest.php
+++ b/core/modules/block/src/Tests/BlockXssTest.php
@@ -50,9 +50,8 @@ protected function doViewTest() {
     $view->addDisplay('block');
     $view->save();
 
-    $this->drupalGet(Url::fromRoute('block.admin_display'));
-    $this->clickLink('<script>alert("view");</script>');
-    $this->assertRaw('&lt;script&gt;alert(&quot;view&quot;);&lt;/script&gt;');
+    $this->drupalGet(Url::fromRoute('block.admin_layout_add', ['theme' => 'classy']));
+    $this->assertRaw('alert("view");');
     $this->assertNoRaw('<script>alert("view");</script>');
   }
 
@@ -65,9 +64,8 @@ protected function doMenuTest() {
       'label' => '<script>alert("menu");</script>',
     ])->save();
 
-    $this->drupalGet(Url::fromRoute('block.admin_display'));
-    $this->clickLink('<script>alert("menu");</script>');
-    $this->assertRaw('&lt;script&gt;alert(&quot;menu&quot;);&lt;/script&gt;');
+    $this->drupalGet(Url::fromRoute('block.admin_layout_add', ['theme' => 'classy']));
+    $this->assertRaw('alert("menu");');
     $this->assertNoRaw('<script>alert("menu");</script>');
   }
 
@@ -85,9 +83,8 @@ protected function doBlockContentTest() {
       'info' => '<script>alert("block_content");</script>',
     ])->save();
 
-    $this->drupalGet(Url::fromRoute('block.admin_display'));
-    $this->clickLink('<script>alert("block_content");</script>');
-    $this->assertRaw('&lt;script&gt;alert(&quot;block_content&quot;);&lt;/script&gt;');
+    $this->drupalGet(Url::fromRoute('block.admin_layout_add', ['theme' => 'classy']));
+    $this->assertRaw('alert("block_content");');
     $this->assertNoRaw('<script>alert("block_content");</script>');
   }
 
diff --git a/core/modules/block/src/Tests/Views/DisplayBlockTest.php b/core/modules/block/src/Tests/Views/DisplayBlockTest.php
index 3f96ab1..31ed059 100644
--- a/core/modules/block/src/Tests/Views/DisplayBlockTest.php
+++ b/core/modules/block/src/Tests/Views/DisplayBlockTest.php
@@ -8,8 +8,6 @@
 namespace Drupal\block\Tests\Views;
 
 use Drupal\Component\Serialization\Json;
-use Drupal\Component\Utility\Html;
-use Drupal\Component\Utility\SafeMarkup;
 use Drupal\views\Views;
 use Drupal\views\Tests\ViewTestBase;
 use Drupal\views\Tests\ViewTestData;
@@ -60,19 +58,19 @@ public function testBlockCategory() {
     $edit['block[style][row_plugin]'] = 'fields';
     $this->drupalPostForm('admin/structure/views/add', $edit, t('Save and edit'));
 
+    $pattern = '//tr[.//td[text()=:category] and .//td/div/div/ul/li/a[contains(@href, :href)]]';
+
     // Test that the block was given a default category corresponding to its
     // base table.
     $arguments = array(
-      ':id' => 'edit-category-lists-views',
-      ':li_class' => 'views-block' . Html::getClass($edit['id']) . '-block-1',
       ':href' => \Drupal::Url('block.admin_add', array(
         'plugin_id' => 'views_block:' . $edit['id'] . '-block_1',
         'theme' => 'classy',
       )),
-      ':text' => $edit['label'],
+      ':category' => t('Lists (Views)'),
     );
-    $this->drupalGet('admin/structure/block');
-    $elements = $this->xpath('//details[@id=:id]//li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments);
+    $this->drupalGet('admin/structure/block/list/classy/add');
+    $elements = $this->xpath($pattern, $arguments);
     $this->assertTrue(!empty($elements), 'The test block appears in the category for its base table.');
 
     // Duplicate the block before changing the category.
@@ -81,10 +79,9 @@ public function testBlockCategory() {
 
     // Change the block category to a random string.
     $this->drupalGet('admin/structure/views/view/' . $edit['id'] . '/edit/block_1');
-    $label = t('Lists (Views)');
-    $link = $this->xpath('//a[@id="views-block-1-block-category" and normalize-space(text())=:label]', array(':label' => $label));
+    $link = $this->xpath('//a[@id="views-block-1-block-category" and normalize-space(text())=:category]', $arguments);
     $this->assertTrue(!empty($link));
-    $this->clickLink($label);
+    $this->clickLink(t('Lists (Views)'));
     $category = $this->randomString();
     $this->drupalPostForm(NULL, array('block_category' => $category), t('Apply'));
 
@@ -95,34 +92,29 @@ public function testBlockCategory() {
     $this->drupalPostForm(NULL, array(), t('Save'));
 
     // Test that the blocks are listed under the correct categories.
-    $category_id = Html::getUniqueId('edit-category-' . SafeMarkup::checkPlain($category));
-    $arguments[':id'] = $category_id;
-    $this->drupalGet('admin/structure/block');
-    $elements = $this->xpath('//details[@id=:id]//li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments);
+    $arguments[':category'] = $category;
+    $this->drupalGet('admin/structure/block/list/classy/add');
+    $elements = $this->xpath($pattern, $arguments);
     $this->assertTrue(!empty($elements), 'The test block appears in the custom category.');
 
     $arguments = array(
-      ':id' => 'edit-category-lists-views',
-      ':li_class' => 'views-block' . Html::getClass($edit['id']) . '-block-2',
       ':href' => \Drupal::Url('block.admin_add', array(
         'plugin_id' => 'views_block:' . $edit['id'] . '-block_2',
         'theme' => 'classy',
       )),
-      ':text' => $edit['label'],
+      ':category' => t('Lists (Views)'),
     );
-    $elements = $this->xpath('//details[@id=:id]//li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments);
+    $elements = $this->xpath($pattern, $arguments);
     $this->assertTrue(!empty($elements), 'The first duplicated test block remains in the original category.');
 
     $arguments = array(
-      ':id' => $category_id,
-      ':li_class' => 'views-block' . Html::getClass($edit['id']) . '-block-3',
       ':href' => \Drupal::Url('block.admin_add', array(
         'plugin_id' => 'views_block:' . $edit['id'] . '-block_3',
         'theme' => 'classy',
       )),
-      ':text' => $edit['label'],
+      ':category' => $category,
     );
-    $elements = $this->xpath('//details[@id=:id]//li[contains(@class, :li_class)]/a[contains(@href, :href) and text()=:text]', $arguments);
+    $elements = $this->xpath($pattern, $arguments);
     $this->assertTrue(!empty($elements), 'The second duplicated test block appears in the custom category.');
   }
 
diff --git a/core/modules/block_content/block_content.links.action.yml b/core/modules/block_content/block_content.links.action.yml
index d94ca3f..b55361a 100644
--- a/core/modules/block_content/block_content.links.action.yml
+++ b/core/modules/block_content/block_content.links.action.yml
@@ -8,7 +8,5 @@ block_content_add_action:
   route_name: block_content.add_page
   title: 'Add custom block'
   appears_on:
-    - block.admin_display
-    - block.admin_display_theme
     - entity.block_content.collection
   class: \Drupal\block_content\Plugin\Menu\LocalAction\BlockContentAddLocalAction
diff --git a/core/modules/block_content/block_content.links.task.yml b/core/modules/block_content/block_content.links.task.yml
index 2b88171..e6b0545 100644
--- a/core/modules/block_content/block_content.links.task.yml
+++ b/core/modules/block_content/block_content.links.task.yml
@@ -1,5 +1,5 @@
 entity.block_content.collection:
-  title: 'Custom block library'
+  title: 'Custom blocks'
   route_name: entity.block_content.collection
   base_route: block.admin_display
 block_content.list_sub:
diff --git a/core/modules/block_content/block_content.routing.yml b/core/modules/block_content/block_content.routing.yml
index 3542ca8..fc48fb1 100644
--- a/core/modules/block_content/block_content.routing.yml
+++ b/core/modules/block_content/block_content.routing.yml
@@ -2,7 +2,7 @@ entity.block_content_type.collection:
   path: '/admin/structure/block/block-content/types'
   defaults:
     _entity_list: 'block_content_type'
-    _title: 'Custom block library'
+    _title: 'Custom blocks'
   requirements:
     _permission: 'administer blocks'
 
@@ -83,7 +83,7 @@ entity.block_content_type.edit_form:
 entity.block_content.collection:
   path: '/admin/structure/block/block-content'
   defaults:
-    _title: 'Custom block library'
+    _title: 'Custom blocks'
     _entity_list: 'block_content'
   requirements:
     _permission: 'administer blocks'
diff --git a/core/modules/block_content/src/Tests/BlockContentListTest.php b/core/modules/block_content/src/Tests/BlockContentListTest.php
index aeed4dc..30d1585 100644
--- a/core/modules/block_content/src/Tests/BlockContentListTest.php
+++ b/core/modules/block_content/src/Tests/BlockContentListTest.php
@@ -33,7 +33,7 @@ public function testListing() {
     $this->drupalGet('admin/structure/block/block-content');
 
     // Test for the page title.
-    $this->assertTitle(t('Custom block library') . ' | Drupal');
+    $this->assertTitle(t('Custom blocks') . ' | Drupal');
 
     // Test for the table.
     $element = $this->xpath('//div[@class="layout-content"]//table');
diff --git a/core/modules/block_content/src/Tests/BlockContentTypeTest.php b/core/modules/block_content/src/Tests/BlockContentTypeTest.php
index 4270538..33fcfed 100644
--- a/core/modules/block_content/src/Tests/BlockContentTypeTest.php
+++ b/core/modules/block_content/src/Tests/BlockContentTypeTest.php
@@ -185,20 +185,10 @@ public function testsBlockContentAddTypes() {
       // For each installed theme, go to its block page and test the redirects.
       $themes = array('bartik', 'classy', 'seven');
       foreach ($themes as $theme) {
-        // Test that adding a block from the 'place blocks' form sends you to the
+        // Test that adding a block from a 'custom block' link sends you to the
         // block configure form.
-        $path = $theme == $default_theme ? 'admin/structure/block' : "admin/structure/block/list/$theme";
-        $this->drupalGet($path);
-        $this->clickLink(t('Add custom block'));
-        // The seven theme has markup inside the link, we cannot use clickLink().
-        if ($default_theme == 'seven') {
-          $options = $theme != $default_theme ? array('query' => array('theme' => $theme)) : array();
-          $this->assertLinkByHref(\Drupal::url('block_content.add_form', array('block_content_type' => 'foo'), $options));
-          $this->drupalGet('block/add/foo', $options);
-        }
-        else {
-          $this->clickLink('foo');
-        }
+        $this->drupalGet('block/add', ['query' => ['theme' => $theme]]);
+        $this->clickLink('foo');
         // Create a new block.
         $edit = array('info[0][value]' => $this->randomMachineName(8));
         $this->drupalPostForm(NULL, $edit, t('Save'));
diff --git a/core/modules/menu_ui/src/Tests/MenuTest.php b/core/modules/menu_ui/src/Tests/MenuTest.php
index 3a1bac5..3c023bb 100644
--- a/core/modules/menu_ui/src/Tests/MenuTest.php
+++ b/core/modules/menu_ui/src/Tests/MenuTest.php
@@ -181,7 +181,7 @@ function addCustomMenuCRUD() {
    * @return \Drupal\system\Entity\Menu
    *   The custom menu that has been created.
    */
-  function addCustomMenu() {
+  protected function addCustomMenu() {
     // Try adding a menu using a menu_name that is too long.
     $this->drupalGet('admin/structure/menu/add');
     $menu_name = substr(hash('sha256', $this->randomMachineName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI + 1);
@@ -218,7 +218,7 @@ function addCustomMenu() {
     $this->assertText($label, 'Menu created');
 
     // Confirm that the custom menu block is available.
-    $this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default'));
+    $this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default') . '/add');
     $this->assertText($label);
 
     // Enable the block.
@@ -531,7 +531,7 @@ function testSystemMenuRename() {
 
     // Make sure menu shows up with new name in block addition.
     $default_theme = $this->config('system.theme')->get('default');
-    $this->drupalget('admin/structure/block/list/' . $default_theme);
+    $this->drupalget('admin/structure/block/list/' . $default_theme . '/add');
     $this->assertText($edit['label']);
   }
 
diff --git a/core/modules/search/src/Tests/SearchBlockTest.php b/core/modules/search/src/Tests/SearchBlockTest.php
index bf18056..5978f22 100644
--- a/core/modules/search/src/Tests/SearchBlockTest.php
+++ b/core/modules/search/src/Tests/SearchBlockTest.php
@@ -35,7 +35,7 @@ protected function setUp() {
   public function testSearchFormBlock() {
 
     // Test availability of the search block in the admin "Place blocks" list.
-    $this->drupalGet('admin/structure/block');
+    $this->drupalGet('admin/structure/block/list/classy/add');
     $this->assertLinkByHref('/admin/structure/block/add/search_form_block/classy', 0,
       'Did not find the search block in block candidate list.');
 
diff --git a/core/modules/views/src/Tests/Wizard/BasicTest.php b/core/modules/views/src/Tests/Wizard/BasicTest.php
index d55b941..5362854 100644
--- a/core/modules/views/src/Tests/Wizard/BasicTest.php
+++ b/core/modules/views/src/Tests/Wizard/BasicTest.php
@@ -132,7 +132,7 @@ function testViewsWizardAndListing() {
     $this->assertNoText('REST export', 'If only the page and block options were enabled in the wizard, the resulting view does not have a REST export display.');
 
     // Confirm that the block is available in the block administration UI.
-    $this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default'));
+    $this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default') . '/add');
     $this->assertText($view3['label']);
 
     // Place the block.
diff --git a/core/modules/views/src/Tests/Wizard/ItemsPerPageTest.php b/core/modules/views/src/Tests/Wizard/ItemsPerPageTest.php
index 8e8edfc..c14cd81 100644
--- a/core/modules/views/src/Tests/Wizard/ItemsPerPageTest.php
+++ b/core/modules/views/src/Tests/Wizard/ItemsPerPageTest.php
@@ -70,7 +70,7 @@ function testItemsPerPage() {
     $this->assertTrue($pos5 < $pos4 && $pos4 < $pos3 && $pos3 < $pos2, 'The nodes appear in the expected order in the page display.');
 
     // Confirm that the block is listed in the block administration UI.
-    $this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default'));
+    $this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default') . '/add');
     $this->assertText($view['label']);
 
     // Place the block, visit a page that displays the block, and check that the
diff --git a/core/modules/views_ui/src/Tests/OverrideDisplaysTest.php b/core/modules/views_ui/src/Tests/OverrideDisplaysTest.php
index f1815a8..4b50766 100644
--- a/core/modules/views_ui/src/Tests/OverrideDisplaysTest.php
+++ b/core/modules/views_ui/src/Tests/OverrideDisplaysTest.php
@@ -49,7 +49,7 @@ function testOverrideDisplays() {
     $this->assertText($original_title);
 
     // Confirm that the view block is available in the block administration UI.
-    $this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default'));
+    $this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default') . '/add');
     $this->assertText($view['label']);
 
     // Place the block.
@@ -108,7 +108,7 @@ function testWizardMixedDefaultOverriddenDisplays() {
     $this->assertNoText($view['block[title]']);
 
     // Confirm that the block is available in the block administration UI.
-    $this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default'));
+    $this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default') . '/add');
     $this->assertText($view['label']);
 
     // Put the block into the first sidebar region, and make sure it will not
