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/js/block.admin.js b/core/modules/block/js/block.admin.js
index 23109f4..a8edb87 100644
--- a/core/modules/block/js/block.admin.js
+++ b/core/modules/block/js/block.admin.js
@@ -19,66 +19,37 @@
   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();
-
+        
         /**
          * 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.
+        
         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..27f6bc7 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,76 @@ 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) {
+    $header = [
+      t('Block'),
+      t('Category'),
+      t('Operations'),
+    ];
+    $rows = [];
+    
+    // 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) {
+      $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' => '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' => t('Filter'),
+      '#title_display' => 'invisible',
+      '#size' => 30,
+      '#placeholder' => t('Filter by block name'),
+      '#attributes' => [
+        'class' => ['block-filter-text'],
+        'data-element' => '.block-add-table',
+        'title' => t('Enter a part of the block name to filter by.'),
+      ],
+    );
+    
+    $build['blocks'] = [
+      '#type' => 'table',
+      '#header' => $header,
+      '#rows' => $rows,
+      '#empty' => t('No blocks available.'),
+      '#attributes' => [
+        'class' => ['block-add-table'],
+      ],
+    ];
+    
+    return $build;
+  }
+  
 }
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'
