diff --git a/core/composer.json b/core/composer.json
index 7452a07776..770631ddfd 100644
--- a/core/composer.json
+++ b/core/composer.json
@@ -133,6 +133,7 @@
         "drupal/locale": "self.version",
         "drupal/minimal": "self.version",
         "drupal/media": "self.version",
+        "drupal/media_library": "self.version",
         "drupal/menu_link_content": "self.version",
         "drupal/menu_ui": "self.version",
         "drupal/migrate": "self.version",
diff --git a/core/modules/media_library/config/install/core.entity_view_mode.media.media_library.yml b/core/modules/media_library/config/install/core.entity_view_mode.media.media_library.yml
new file mode 100644
index 0000000000..3406f026b4
--- /dev/null
+++ b/core/modules/media_library/config/install/core.entity_view_mode.media.media_library.yml
@@ -0,0 +1,12 @@
+langcode: en
+status: true
+dependencies:
+  enforced:
+    module:
+      - media_library
+  module:
+    - media
+id: media.media_library
+label: 'Media library'
+targetEntityType: media
+cache: true
diff --git a/core/modules/media_library/config/install/views.view.media_library.yml b/core/modules/media_library/config/install/views.view.media_library.yml
new file mode 100644
index 0000000000..db19773062
--- /dev/null
+++ b/core/modules/media_library/config/install/views.view.media_library.yml
@@ -0,0 +1,498 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - core.entity_view_mode.media.media_library
+  enforced:
+    module:
+      - media_library
+  module:
+    - media
+    - user
+id: media_library
+label: 'Media library'
+module: views
+description: ''
+tag: ''
+base_table: media_field_data
+base_field: mid
+core: 8.x
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: 0
+    display_options:
+      access:
+        type: perm
+        options:
+          perm: 'access media overview'
+      cache:
+        type: tag
+        options: {  }
+      query:
+        type: views_query
+        options:
+          disable_sql_rewrite: false
+          distinct: false
+          replica: false
+          query_comment: ''
+          query_tags: {  }
+      exposed_form:
+        type: basic
+        options:
+          submit_button: 'Apply Filters'
+          reset_button: false
+          reset_button_label: Reset
+          exposed_sorts_label: 'Sort by'
+          expose_sort_order: false
+          sort_asc_label: Asc
+          sort_desc_label: Desc
+      pager:
+        type: mini
+        options:
+          items_per_page: 25
+          offset: 0
+          id: 0
+          total_pages: null
+          expose:
+            items_per_page: false
+            items_per_page_label: 'Items per page'
+            items_per_page_options: '5, 10, 25, 50'
+            items_per_page_options_all: false
+            items_per_page_options_all_label: '- All -'
+            offset: false
+            offset_label: Offset
+          tags:
+            previous: ‹‹
+            next: ››
+      style:
+        type: default
+        options:
+          grouping: {  }
+          row_class: 'media-library-item click-to-select'
+          default_row_class: true
+      row:
+        type: fields
+        options:
+          default_field_elements: true
+          inline: {  }
+          separator: ''
+          hide_empty: false
+      fields:
+        media_bulk_form:
+          id: media_bulk_form
+          table: media
+          field: media_bulk_form
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: click-to-select-checkbox
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          action_title: Action
+          include_exclude: exclude
+          selected_actions: {  }
+          entity_type: media
+          plugin_id: bulk_form
+        rendered_entity:
+          id: rendered_entity
+          table: media
+          field: rendered_entity
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: media-library-item__content
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          view_mode: media_library
+          entity_type: media
+          plugin_id: rendered_entity
+        operations:
+          id: operations
+          table: media
+          field: operations
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          destination: false
+          entity_type: media
+          plugin_id: entity_operations
+      filters:
+        status:
+          id: status
+          table: media_field_data
+          field: status
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '='
+          value: '1'
+          group: 1
+          exposed: true
+          expose:
+            operator_id: ''
+            label: 'Publishing status'
+            description: null
+            use_operator: false
+            operator: status_op
+            identifier: status
+            required: true
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+          is_grouped: true
+          group_info:
+            label: Published
+            description: ''
+            identifier: status
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items:
+              1:
+                title: Published
+                operator: '='
+                value: '1'
+              2:
+                title: Unpublished
+                operator: '='
+                value: '0'
+          plugin_id: boolean
+          entity_type: media
+          entity_field: status
+        name:
+          id: name
+          table: media_field_data
+          field: name
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: contains
+          value: ''
+          group: 1
+          exposed: true
+          expose:
+            operator_id: name_op
+            label: Name
+            description: ''
+            use_operator: false
+            operator: name_op
+            identifier: name
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: media
+          entity_field: name
+          plugin_id: string
+        bundle:
+          id: bundle
+          table: media_field_data
+          field: bundle
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: in
+          value: {  }
+          group: 1
+          exposed: true
+          expose:
+            operator_id: bundle_op
+            label: 'Media type'
+            description: ''
+            use_operator: false
+            operator: bundle_op
+            identifier: type
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+              anonymous: '0'
+              administrator: '0'
+            reduce: false
+          is_grouped: false
+          group_info:
+            label: 'Media type'
+            description: null
+            identifier: bundle
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items:
+              1: {  }
+              2: {  }
+              3: {  }
+          entity_type: media
+          entity_field: bundle
+          plugin_id: bundle
+      sorts:
+        created:
+          id: created
+          table: media_field_data
+          field: created
+          relationship: none
+          group_type: group
+          admin_label: ''
+          order: DESC
+          exposed: true
+          expose:
+            label: 'Newest first'
+          granularity: second
+          entity_type: media
+          entity_field: created
+          plugin_id: date
+        name:
+          id: name
+          table: media_field_data
+          field: name
+          relationship: none
+          group_type: group
+          admin_label: ''
+          order: ASC
+          exposed: true
+          expose:
+            label: 'Name (A-Z)'
+          entity_type: media
+          entity_field: name
+          plugin_id: standard
+        name_1:
+          id: name_1
+          table: media_field_data
+          field: name
+          relationship: none
+          group_type: group
+          admin_label: ''
+          order: DESC
+          exposed: true
+          expose:
+            label: 'Name (Z-A)'
+          entity_type: media
+          entity_field: name
+          plugin_id: standard
+      title: Media
+      header: {  }
+      footer: {  }
+      empty: {  }
+      relationships: {  }
+      arguments:
+        bundle:
+          id: bundle
+          table: media_field_data
+          field: bundle
+          relationship: none
+          group_type: group
+          admin_label: ''
+          default_action: ignore
+          exception:
+            value: all
+            title_enable: false
+            title: All
+          title_enable: false
+          title: ''
+          default_argument_type: fixed
+          default_argument_options:
+            argument: ''
+          default_argument_skip_url: false
+          summary_options:
+            base_path: ''
+            count: true
+            items_per_page: 25
+            override: false
+          summary:
+            sort_order: asc
+            number_of_records: 0
+            format: default_summary
+          specify_validation: false
+          validate:
+            type: none
+            fail: 'not found'
+          validate_options: {  }
+          glossary: false
+          limit: 0
+          case: none
+          path_case: none
+          transform_dash: false
+          break_phrase: false
+          entity_type: media
+          entity_field: bundle
+          plugin_id: string
+      display_extenders: {  }
+      use_ajax: true
+      css_class: media-library-view
+    cache_metadata:
+      max-age: 0
+      contexts:
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - 'url.query_args:sort_by'
+        - user.permissions
+      tags: {  }
+  page:
+    display_plugin: page
+    id: page
+    display_title: Page
+    position: 1
+    display_options:
+      display_extenders: {  }
+      path: admin/content/media
+      menu:
+        type: tab
+        title: Media
+        description: 'Allows users to browse and administer media items'
+        expanded: false
+        parent: system.admin_content
+        weight: 5
+        context: '0'
+        menu_name: admin
+    cache_metadata:
+      max-age: 0
+      contexts:
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - 'url.query_args:sort_by'
+        - user.permissions
+      tags: {  }
diff --git a/core/modules/media_library/config/optional/core.entity_view_display.media.audio.media_library.yml b/core/modules/media_library/config/optional/core.entity_view_display.media.audio.media_library.yml
new file mode 100644
index 0000000000..e74e3ebde6
--- /dev/null
+++ b/core/modules/media_library/config/optional/core.entity_view_display.media.audio.media_library.yml
@@ -0,0 +1,29 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - core.entity_view_mode.media.media_library
+    - field.field.media.audio.field_media_audio_file
+    - image.style.thumbnail
+    - media.type.audio
+  module:
+    - image
+id: media.audio.media_library
+targetEntityType: media
+bundle: audio
+mode: media_library
+content:
+  thumbnail:
+    type: image
+    weight: 0
+    region: content
+    label: hidden
+    settings:
+      image_style: thumbnail
+      image_link: ''
+    third_party_settings: {  }
+hidden:
+  created: true
+  field_media_audio_file: true
+  name: true
+  uid: true
diff --git a/core/modules/media_library/config/optional/core.entity_view_display.media.file.media_library.yml b/core/modules/media_library/config/optional/core.entity_view_display.media.file.media_library.yml
new file mode 100644
index 0000000000..e09e611b95
--- /dev/null
+++ b/core/modules/media_library/config/optional/core.entity_view_display.media.file.media_library.yml
@@ -0,0 +1,29 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - core.entity_view_mode.media.media_library
+    - field.field.media.file.field_media_file
+    - image.style.thumbnail
+    - media.type.file
+  module:
+    - image
+id: media.file.media_library
+targetEntityType: media
+bundle: file
+mode: media_library
+content:
+  thumbnail:
+    type: image
+    weight: 0
+    region: content
+    label: hidden
+    settings:
+      image_style: thumbnail
+      image_link: ''
+    third_party_settings: {  }
+hidden:
+  created: true
+  field_media_file: true
+  name: true
+  uid: true
diff --git a/core/modules/media_library/config/optional/core.entity_view_display.media.image.media_library.yml b/core/modules/media_library/config/optional/core.entity_view_display.media.image.media_library.yml
new file mode 100644
index 0000000000..a916760ad9
--- /dev/null
+++ b/core/modules/media_library/config/optional/core.entity_view_display.media.image.media_library.yml
@@ -0,0 +1,29 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - core.entity_view_mode.media.media_library
+    - field.field.media.image.field_media_image
+    - image.style.medium
+    - media.type.image
+  module:
+    - image
+id: media.image.media_library
+targetEntityType: media
+bundle: image
+mode: media_library
+content:
+  thumbnail:
+    type: image
+    weight: 0
+    region: content
+    label: hidden
+    settings:
+      image_style: medium
+      image_link: ''
+    third_party_settings: {  }
+hidden:
+  created: true
+  field_media_image: true
+  name: true
+  uid: true
diff --git a/core/modules/media_library/config/optional/core.entity_view_display.media.video.media_library.yml b/core/modules/media_library/config/optional/core.entity_view_display.media.video.media_library.yml
new file mode 100644
index 0000000000..33d4e88555
--- /dev/null
+++ b/core/modules/media_library/config/optional/core.entity_view_display.media.video.media_library.yml
@@ -0,0 +1,29 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - core.entity_view_mode.media.media_library
+    - field.field.media.video.field_media_video_file
+    - image.style.thumbnail
+    - media.type.video
+  module:
+    - image
+id: media.video.media_library
+targetEntityType: media
+bundle: video
+mode: media_library
+content:
+  thumbnail:
+    type: image
+    weight: 0
+    region: content
+    label: hidden
+    settings:
+      image_style: thumbnail
+      image_link: ''
+    third_party_settings: {  }
+hidden:
+  created: true
+  field_media_video_file: true
+  name: true
+  uid: true
diff --git a/core/modules/media_library/css/media_library.module.css b/core/modules/media_library/css/media_library.module.css
new file mode 100644
index 0000000000..0b897ee363
--- /dev/null
+++ b/core/modules/media_library/css/media_library.module.css
@@ -0,0 +1,53 @@
+/**
+* @file media_library.module.css
+*/
+
+.media-library-view .view-content form {
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.media-library-view .view-content form > [id*="edit-actions"] {
+  flex-basis: 100%;
+}
+
+.media-library-view .view-content [id*="edit-header"] > div,
+.media-library-view .form--inline {
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.media-library-view .view-content [id*="edit-header"] {
+  flex-basis: 100%;
+}
+
+.media-library-item .click-to-select-trigger {
+  overflow: hidden;
+  cursor: pointer;
+}
+
+.media-library-view .form-actions {
+  align-self: flex-end;
+}
+
+.media-library-item .click-to-select-checkbox {
+  position: absolute;
+  display: block;
+  z-index: 1;
+  top: 0;
+  left: 0;
+  padding: 10px;
+}
+
+.media-library-item .media-library-item__status {
+  position: absolute;
+  top: 15px;
+  right: 2px;
+  pointer-events: none;
+}
+
+@media screen and (max-width: 600px) {
+  .media-library-view .form-actions {
+    flex-basis: 100%;
+  }
+}
diff --git a/core/modules/media_library/css/media_library.theme.css b/core/modules/media_library/css/media_library.theme.css
new file mode 100644
index 0000000000..586d0da006
--- /dev/null
+++ b/core/modules/media_library/css/media_library.theme.css
@@ -0,0 +1,139 @@
+/**
+* @file media_library.theme.css
+*/
+
+.media-library-view .view-content [id*="edit-header"] .form-item {
+  margin-right: 8px;
+}
+
+#drupal-modal .view-header {
+  margin: 16px 0;
+}
+
+.media-library-item {
+  position: relative;
+  justify-content: center;
+  vertical-align: top;
+  padding: 2px;
+  border: 1px solid #ebebeb;
+  margin: 16px 16px 2px 2px;
+  width: 180px;
+  background: #ffffff;
+  transition: border-color .2s, color .2s, background .2s;
+}
+
+.media-library-view .form-actions {
+  margin: 0.75em 0;
+}
+
+.media-library-item .field--name-thumbnail {
+  background-color: #ebebeb;
+  margin: 2px;
+  overflow: hidden;
+  text-align: center;
+}
+
+.media-library-item .field--name-thumbnail img {
+  height: 180px;
+  object-fit: contain;
+  object-position: center center;
+}
+
+.media-library-item.is-hover {
+  border-color: #40b6ff;
+  border-width: 3px;
+  border-radius: 3px;
+  margin: 14px 14px 0 0;
+}
+
+.media-library-item.checked {
+  border-radius: 3px;
+  background: #0076c0;
+  color: white;
+}
+
+.media-library-item.checked .media-library-item__attributes * {
+  color: white;
+}
+
+.media-library-item.checked a {
+  color: white;
+}
+
+.media-library-item .click-to-select-checkbox input {
+  width: 30px;
+  height: 30px;
+}
+
+.media-library-item .click-to-select-checkbox .form-item {
+  margin: 0;
+}
+
+.media-library-item .media-library-item__status {
+  color: #e4e4e4;
+  font-style: italic;
+  background: #666666;
+  padding: 5px 15px;
+  font-size: 12px;
+}
+
+.media-library-item .views-field-operations {
+  height: 30px;
+}
+
+.media-library-item .views-field-operations .dropbutton-wrapper {
+  display: inline-block;
+  position: absolute;
+  right: 5px;
+  bottom: 5px;
+}
+
+.media-library-item__attributes {
+  margin: 10px 30px 15px 10px;
+}
+
+.media-library-item__name {
+  font-size: 14px;
+  max-height: 60px;
+  overflow: hidden;
+  padding-bottom: 4px;
+}
+
+.media-library-item__name a {
+  display: block;
+  text-decoration: underline;
+  margin: 2px;
+}
+
+.media-library-item__name a:focus {
+  border: 2px solid;
+  margin: 0;
+}
+
+.media-library-item__type {
+  font-size: 12px;
+  color: #696969;
+}
+
+@media screen and (max-width: 600px) {
+  .media-library-item {
+    width: 150px;
+  }
+  .media-library-item .field--name-thumbnail img {
+    height: 150px;
+    width: 150px;
+  }
+  .media-library-item .views-field-operations .dropbutton-wrapper {
+    position: relative;
+    right: 0;
+    border: 0;
+  }
+  .media-library-select-all {
+    float: none;
+    margin-left: 0;
+    margin-right: 0;
+    margin-top: 10px;
+    padding-bottom: 6px;
+    width: 100%;
+  }
+}
diff --git a/core/modules/media_library/js/media_library.click_to_select.es6.js b/core/modules/media_library/js/media_library.click_to_select.es6.js
new file mode 100644
index 0000000000..2f08e9be67
--- /dev/null
+++ b/core/modules/media_library/js/media_library.click_to_select.es6.js
@@ -0,0 +1,27 @@
+/**
+ * @file media_library.click_to_select.es6.js
+ */
+
+(($, Drupal) => {
+  /**
+   * Allows users to select an element which checks a hidden checkbox.
+   */
+  Drupal.behaviors.ClickToSelect = {
+    attach(context) {
+      $('.click-to-select .click-to-select-trigger', context)
+        .once('click-to-select')
+        .on('click', (event) => {
+          // Links inside the trigger should not be click-able.
+          event.preventDefault();
+          // Click the hidden checkbox when the trigger is clicked.
+          const $input = $(event.currentTarget).closest('.click-to-select').find('.click-to-select-checkbox input');
+          $input.prop('checked', !$input.prop('checked')).trigger('change');
+        });
+      $('.click-to-select .click-to-select-checkbox input', context)
+        .once('click-to-select')
+        .on('change', (event) => {
+          $(event.currentTarget).closest('.click-to-select').toggleClass('checked', $(event.currentTarget).prop('checked'));
+        });
+    },
+  };
+})(jQuery, Drupal);
diff --git a/core/modules/media_library/js/media_library.click_to_select.js b/core/modules/media_library/js/media_library.click_to_select.js
new file mode 100644
index 0000000000..af5a36252f
--- /dev/null
+++ b/core/modules/media_library/js/media_library.click_to_select.js
@@ -0,0 +1,22 @@
+/**
+* DO NOT EDIT THIS FILE.
+* See the following change record for more information,
+* https://www.drupal.org/node/2815083
+* @preserve
+**/
+
+(function ($, Drupal) {
+  Drupal.behaviors.ClickToSelect = {
+    attach: function attach(context) {
+      $('.click-to-select .click-to-select-trigger', context).once('click-to-select').on('click', function (event) {
+        event.preventDefault();
+
+        var $input = $(event.currentTarget).closest('.click-to-select').find('.click-to-select-checkbox input');
+        $input.prop('checked', !$input.prop('checked')).trigger('change');
+      });
+      $('.click-to-select .click-to-select-checkbox input', context).once('click-to-select').on('change', function (event) {
+        $(event.currentTarget).closest('.click-to-select').toggleClass('checked', $(event.currentTarget).prop('checked'));
+      });
+    }
+  };
+})(jQuery, Drupal);
\ No newline at end of file
diff --git a/core/modules/media_library/js/media_library.view.es6.js b/core/modules/media_library/js/media_library.view.es6.js
new file mode 100644
index 0000000000..913e065509
--- /dev/null
+++ b/core/modules/media_library/js/media_library.view.es6.js
@@ -0,0 +1,46 @@
+/**
+ * @file media_library.view.js
+ */
+(($, Drupal) => {
+  /**
+   * Adds hover effect to media items.
+   */
+  Drupal.behaviors.MediaLibraryHover = {
+    attach(context) {
+      $('.media-library-item .media-library-item__preview', context).once('media-library-item')
+        .on('mouseover focus', ({ currentTarget }) => {
+          $(currentTarget).closest('.media-library-item').addClass('is-hover');
+        })
+        .on('mouseout blur', ({ currentTarget }) => {
+          $(currentTarget).closest('.media-library-item').removeClass('is-hover');
+        });
+    },
+  };
+
+  /**
+   * Adds checkbox to select all items in the library.
+   */
+  Drupal.behaviors.MediaLibrarySelectAll = {
+    attach(context) {
+      const $view = $('.media-library-view', context).once('media-library-select-all');
+      if ($view.length && $view.find('.media-library-item').length) {
+        const strings = {
+          select: Drupal.t('Select all'),
+          deselect: Drupal.t('Deselect all'),
+        };
+        const $button = $('<a class="button media-library-select-all" aria-pressed="false"></a>')
+          .text(strings.select)
+          .on('click', ({ currentTarget }) => {
+            const pressed = $(currentTarget).attr('aria-pressed') === 'true';
+            $(currentTarget).attr('aria-pressed', pressed ? 'false' : 'true');
+            $(currentTarget).text(pressed ? strings.select : strings.deselect);
+            $(currentTarget).closest('.media-library-view')
+              .find('.media-library-item input[type="checkbox"]')
+              .prop('checked', pressed ? false : 'checked')
+              .trigger('change');
+          });
+        $('.media-library-view .view-content [id*="edit-header"] .form-actions').prepend($button)
+      }
+    },
+  };
+})(jQuery, Drupal);
diff --git a/core/modules/media_library/js/media_library.view.js b/core/modules/media_library/js/media_library.view.js
new file mode 100644
index 0000000000..bde7b38aa8
--- /dev/null
+++ b/core/modules/media_library/js/media_library.view.js
@@ -0,0 +1,43 @@
+/**
+* DO NOT EDIT THIS FILE.
+* See the following change record for more information,
+* https://www.drupal.org/node/2815083
+* @preserve
+**/
+
+(function ($, Drupal) {
+  Drupal.behaviors.MediaLibraryHover = {
+    attach: function attach(context) {
+      $('.media-library-item .media-library-item__preview', context).once('media-library-item').on('mouseover focus', function (_ref) {
+        var currentTarget = _ref.currentTarget;
+
+        $(currentTarget).closest('.media-library-item').addClass('is-hover');
+      }).on('mouseout blur', function (_ref2) {
+        var currentTarget = _ref2.currentTarget;
+
+        $(currentTarget).closest('.media-library-item').removeClass('is-hover');
+      });
+    }
+  };
+
+  Drupal.behaviors.MediaLibrarySelectAll = {
+    attach: function attach(context) {
+      var $view = $('.media-library-view', context).once('media-library-select-all');
+      if ($view.length && $view.find('.media-library-item').length) {
+        var strings = {
+          select: Drupal.t('Select all'),
+          deselect: Drupal.t('Deselect all')
+        };
+        var $button = $('<a class="button media-library-select-all" aria-pressed="false"></a>').text(strings.select).on('click', function (_ref3) {
+          var currentTarget = _ref3.currentTarget;
+
+          var pressed = $(currentTarget).attr('aria-pressed') === 'true';
+          $(currentTarget).attr('aria-pressed', pressed ? 'false' : 'true');
+          $(currentTarget).text(pressed ? strings.select : strings.deselect);
+          $(currentTarget).closest('.media-library-view').find('.media-library-item input[type="checkbox"]').prop('checked', pressed ? false : 'checked').trigger('change');
+        });
+        $('.media-library-view .view-content [id*="edit-header"] .form-actions').prepend($button);
+      }
+    }
+  };
+})(jQuery, Drupal);
\ No newline at end of file
diff --git a/core/modules/media_library/media_library.info.yml b/core/modules/media_library/media_library.info.yml
new file mode 100644
index 0000000000..9f7aa912e4
--- /dev/null
+++ b/core/modules/media_library/media_library.info.yml
@@ -0,0 +1,10 @@
+name: 'Media library'
+type: module
+description: 'Provides a library for re-using Media Items.'
+package: Core (Experimental)
+version: VERSION
+core: 8.x
+dependencies:
+  - drupal:media
+  - drupal:views
+  - drupal:user
diff --git a/core/modules/media_library/media_library.install b/core/modules/media_library/media_library.install
new file mode 100644
index 0000000000..9fdf540266
--- /dev/null
+++ b/core/modules/media_library/media_library.install
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the media_library module.
+ */
+
+use Drupal\views\Entity\View;
+
+/**
+ * Implements hook_install().
+ */
+function media_library_install() {
+  // Disable the /admin/content/media view provided by media, so that we can
+  // properly override it.
+  /** @var \Drupal\views\Entity\View $view */
+  if ($view = View::load('media')) {
+    $display = &$view->getDisplay('media_page_list');
+    if (!empty($display)) {
+      $display['display_options']['enabled'] = FALSE;
+      $view->save();
+    }
+  }
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function media_library_uninstall() {
+  // Restore the /admin/content/media view provided by media.
+  /** @var \Drupal\views\Entity\View $view */
+  if ($view = View::load('media')) {
+    $display = &$view->getDisplay('media_page_list');
+    if (!empty($display)) {
+      $display['display_options']['enabled'] = TRUE;
+      $view->save();
+    }
+  }
+}
diff --git a/core/modules/media_library/media_library.libraries.yml b/core/modules/media_library/media_library.libraries.yml
new file mode 100644
index 0000000000..e988dc8ef2
--- /dev/null
+++ b/core/modules/media_library/media_library.libraries.yml
@@ -0,0 +1,25 @@
+style:
+  version: VERSION
+  css:
+    component:
+      css/media_library.module.css: {}
+    theme:
+      css/media_library.theme.css: {}
+
+click_to_select:
+  version: VERSION
+  js:
+    js/media_library.click_to_select.js: {}
+  dependencies:
+    - core/drupal
+    - core/jquery.once
+
+view:
+  version: VERSION
+  js:
+    js/media_library.view.js: {}
+  dependencies:
+    - media_library/style
+    - media_library/click_to_select
+    - core/drupal
+    - core/jquery.once
diff --git a/core/modules/media_library/media_library.links.action.yml b/core/modules/media_library/media_library.links.action.yml
new file mode 100644
index 0000000000..6a37769cf1
--- /dev/null
+++ b/core/modules/media_library/media_library.links.action.yml
@@ -0,0 +1,5 @@
+media_library.add:
+  route_name: entity.media.add_page
+  title: 'Add media'
+  appears_on:
+    - view.media_library.page
diff --git a/core/modules/media_library/media_library.module b/core/modules/media_library/media_library.module
new file mode 100644
index 0000000000..32c3a4f07c
--- /dev/null
+++ b/core/modules/media_library/media_library.module
@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * @file
+ * Contains hook implementations for the media_library module.
+ */
+
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\views\Plugin\views\cache\CachePluginBase;
+use Drupal\views\ViewExecutable;
+use Drupal\Core\Template\Attribute;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element;
+
+/**
+ * Implements hook_help().
+ *
+ * @todo Update in https://www.drupal.org/project/drupal/issues/2964789
+ */
+function media_library_help($route_name, RouteMatchInterface $route_match) {
+  switch ($route_name) {
+    case 'help.page.media_library':
+      $output = '<h3>' . t('About') . '</h3>';
+      $output .= '<p>' . t('The Media library module overrides the /admin/content/media view to provide a rich visual interface for performing administrative operations on media. For more information, see the <a href=":media">online documentation for the Media library module</a>.', [':media' => 'https://www.drupal.org/docs/8/core/modules/media']) . '</p>';
+      return $output;
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function media_library_theme() {
+  return [
+    'media__media_library' => [
+      'base hook' => 'media',
+    ],
+  ];
+}
+
+/**
+ * Implements hook_views_post_render().
+ */
+function media_library_views_post_render(ViewExecutable $view, &$output, CachePluginBase $cache) {
+  if ($view->id() === 'media_library') {
+    $output['#attached']['library'][] = 'media_library/view';
+  }
+}
+
+/**
+ * Implements hook_preprocess_media().
+ */
+function media_library_preprocess_media(&$variables) {
+  if ($variables['view_mode'] === 'media_library') {
+    /** @var \Drupal\media\MediaInterface $media */
+    $media = $variables['media'];
+    $variables['url'] = $media->toUrl('canonical', [
+      'language' => $media->language(),
+    ]);
+    $variables['preview_attributes'] = new Attribute();
+    $variables['preview_attributes']->addClass('media-library-item__preview', 'click-to-select-trigger');
+    $variables['metadata_attributes'] = new Attribute();
+    $variables['metadata_attributes']->addClass('media-library-item__attributes');
+    $variables['status'] = $media->isPublished();
+  }
+}
+
+/**
+ * Alter the bulk form to add a more accessible label.
+ *
+ * @todo Remove in https://www.drupal.org/project/drupal/issues/2969660
+ *
+ * @param array $form
+ *   An associative array containing the structure of the form.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *   The current state of the form.
+ */
+function media_library_form_views_form_media_library_page_alter(array &$form, FormStateInterface $form_state) {
+  if (isset($form['media_bulk_form']) && isset($form['output'])) {
+    /** @var \Drupal\views\ViewExecutable $view */
+    $view = $form['output'][0]['#view'];
+    foreach (Element::getVisibleChildren($form['media_bulk_form']) as $key) {
+      if (isset($view->result[$key])) {
+        $media = $view->field['media_bulk_form']->getEntity($view->result[$key]);
+        $form['media_bulk_form'][$key]['#title'] = t('Select @label', [
+          '@label' => $media->label(),
+        ]);
+      }
+    }
+  }
+}
diff --git a/core/modules/media_library/templates/media--media-library.html.twig b/core/modules/media_library/templates/media--media-library.html.twig
new file mode 100644
index 0000000000..49798a5b51
--- /dev/null
+++ b/core/modules/media_library/templates/media--media-library.html.twig
@@ -0,0 +1,51 @@
+{#
+/**
+ * @file
+ * Default theme implementation to present a media entity in the media library.
+ *
+ * Available variables:
+ * - media: The entity with limited access to object properties and methods.
+ *   Only method names starting with "get", "has", or "is" and a few common
+ *   methods such as "id", "label", and "bundle" are available. For example:
+ *   - entity.getEntityTypeId() will return the entity type ID.
+ *   - entity.hasField('field_example') returns TRUE if the entity includes
+ *     field_example. (This does not indicate the presence of a value in this
+ *     field.)
+ *   Calling other methods, such as entity.delete(), will result in an exception.
+ *   See \Drupal\Core\Entity\EntityInterface for a full list of methods.
+ * - name: Name of the media.
+ * - content: Media content.
+ * - title_prefix: Additional output populated by modules, intended to be
+ *   displayed in front of the main title tag that appears in the template.
+ * - title_suffix: Additional output populated by modules, intended to be
+ *   displayed after the main title tag that appears in the template.
+ * - view_mode: View mode; for example, "teaser" or "full".
+ * - attributes: HTML attributes for the containing element.
+ * - title_attributes: Same as attributes, except applied to the main title
+ *   tag that appears in the template.
+ * - url: Direct URL of the media.
+ * - preview_attributes: HTML attributes for the preview wrapper.
+ * - metadata_attributes: HTML attributes for the expandable metadata area.
+ * - status: Whether or not the Media is published.
+ *
+ * @see template_preprocess_media()
+ *
+ * @ingroup themeable
+ */
+#}
+<article{{ attributes }}>
+  {% if content %}
+    <div{{ preview_attributes }}>
+      {{ content|without('name', 'created', 'uid') }}
+    </div>
+    {% if not status %}
+      <div class="media-library-item__status">{{ "unpublished" | t }}</div>
+    {% endif %}
+    <div{{ metadata_attributes }}>
+      <div class="media-library-item__type">{{ media.bundle()|title }}</div>
+      <div class="media-library-item__name">
+        <a href="{{ url }}" rel="bookmark">{{ name }}</a>
+      </div>
+    </div>
+  {% endif %}
+</article>
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_one.default.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_one.default.yml
new file mode 100644
index 0000000000..212daf8187
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_one.default.yml
@@ -0,0 +1,43 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.media.type_one.field_media_test
+    - media.type.type_one
+id: media.type_one.default
+targetEntityType: media
+bundle: type_one
+mode: default
+content:
+  created:
+    type: datetime_timestamp
+    weight: 10
+    region: content
+    settings: {  }
+    third_party_settings: {  }
+  field_media_test:
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+    type: string_textfield
+    weight: 11
+    region: content
+  name:
+    type: string_textfield
+    weight: -5
+    region: content
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+  uid:
+    type: entity_reference_autocomplete
+    weight: 5
+    settings:
+      match_operator: CONTAINS
+      size: 60
+      placeholder: ''
+    region: content
+    third_party_settings: {  }
+hidden: {  }
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_two.default.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_two.default.yml
new file mode 100644
index 0000000000..fabd13b029
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_two.default.yml
@@ -0,0 +1,43 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.media.type_two.field_media_test_1
+    - media.type.type_two
+id: media.type_two.default
+targetEntityType: media
+bundle: type_two
+mode: default
+content:
+  created:
+    type: datetime_timestamp
+    weight: 10
+    region: content
+    settings: {  }
+    third_party_settings: {  }
+  field_media_test_1:
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+    type: string_textfield
+    weight: 11
+    region: content
+  name:
+    type: string_textfield
+    weight: -5
+    region: content
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+  uid:
+    type: entity_reference_autocomplete
+    weight: 5
+    settings:
+      match_operator: CONTAINS
+      size: 60
+      placeholder: ''
+    region: content
+    third_party_settings: {  }
+hidden: {  }
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.media.type_one.default.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.media.type_one.default.yml
new file mode 100644
index 0000000000..95670b3557
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.media.type_one.default.yml
@@ -0,0 +1,50 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.media.type_one.field_media_test
+    - image.style.thumbnail
+    - media.type.type_one
+  module:
+    - image
+    - user
+id: media.type_one.default
+targetEntityType: media
+bundle: type_one
+mode: default
+content:
+  created:
+    label: hidden
+    type: timestamp
+    weight: 0
+    region: content
+    settings:
+      date_format: medium
+      custom_date_format: ''
+      timezone: ''
+    third_party_settings: {  }
+  field_media_test:
+    label: above
+    settings:
+      link_to_entity: true
+    third_party_settings: {  }
+    type: string
+    weight: 6
+    region: content
+  thumbnail:
+    type: image
+    weight: 5
+    label: hidden
+    settings:
+      image_style: thumbnail
+      image_link: ''
+    region: content
+    third_party_settings: {  }
+  uid:
+    label: hidden
+    type: author
+    weight: 0
+    region: content
+    settings: {  }
+    third_party_settings: {  }
+hidden: {  }
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.media.type_two.default.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.media.type_two.default.yml
new file mode 100644
index 0000000000..a884fee4ce
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.media.type_two.default.yml
@@ -0,0 +1,50 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.media.type_two.field_media_test_1
+    - image.style.thumbnail
+    - media.type.type_two
+  module:
+    - image
+    - user
+id: media.type_two.default
+targetEntityType: media
+bundle: type_two
+mode: default
+content:
+  created:
+    label: hidden
+    type: timestamp
+    weight: 0
+    region: content
+    settings:
+      date_format: medium
+      custom_date_format: ''
+      timezone: ''
+    third_party_settings: {  }
+  field_media_test_1:
+    label: above
+    settings:
+      link_to_entity: false
+    third_party_settings: {  }
+    type: string
+    weight: 6
+    region: content
+  thumbnail:
+    type: image
+    weight: 5
+    label: hidden
+    settings:
+      image_style: thumbnail
+      image_link: ''
+    region: content
+    third_party_settings: {  }
+  uid:
+    label: hidden
+    type: author
+    weight: 0
+    region: content
+    settings: {  }
+    third_party_settings: {  }
+hidden: {  }
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_one.field_media_test.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_one.field_media_test.yml
new file mode 100644
index 0000000000..f19207c9e1
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_one.field_media_test.yml
@@ -0,0 +1,18 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.media.field_media_test
+    - media.type.type_one
+id: media.type_one.field_media_test
+field_name: field_media_test
+entity_type: media
+bundle: type_one
+label: field_media_test
+description: ''
+required: false
+translatable: true
+default_value: {  }
+default_value_callback: ''
+settings: {  }
+field_type: string
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_two.field_media_test_1.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_two.field_media_test_1.yml
new file mode 100644
index 0000000000..5b093caf7b
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_two.field_media_test_1.yml
@@ -0,0 +1,18 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.media.field_media_test_1
+    - media.type.type_two
+id: media.type_two.field_media_test_1
+field_name: field_media_test_1
+entity_type: media
+bundle: type_two
+label: field_media_test_1
+description: ''
+required: false
+translatable: true
+default_value: {  }
+default_value_callback: ''
+settings: {  }
+field_type: string
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_test.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_test.yml
new file mode 100644
index 0000000000..40a77916ec
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_test.yml
@@ -0,0 +1,20 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - media
+id: media.field_media_test
+field_name: field_media_test
+entity_type: media
+type: string
+settings:
+  max_length: 255
+  is_ascii: false
+  case_sensitive: false
+module: core
+locked: false
+cardinality: 1
+translatable: true
+indexes: {  }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_test_1.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_test_1.yml
new file mode 100644
index 0000000000..73b11058e4
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_test_1.yml
@@ -0,0 +1,20 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - media
+id: media.field_media_test_1
+field_name: field_media_test_1
+entity_type: media
+type: string
+settings:
+  max_length: 255
+  is_ascii: false
+  case_sensitive: false
+module: core
+locked: false
+cardinality: 1
+translatable: true
+indexes: {  }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_one.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_one.yml
new file mode 100644
index 0000000000..1f72b8beb6
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_one.yml
@@ -0,0 +1,16 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - media
+    - media_test_source
+id: type_one
+label: 'Type One'
+description: ''
+source: test
+queue_thumbnail_downloads: false
+new_revision: false
+source_configuration:
+  source_field: field_media_test
+  test_config_value: 'This is default value.'
+field_map: {  }
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_two.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_two.yml
new file mode 100644
index 0000000000..13b549c6ac
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_two.yml
@@ -0,0 +1,16 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - media
+    - media_test_source
+id: type_two
+label: 'Type Two'
+description: ''
+source: test
+queue_thumbnail_downloads: false
+new_revision: false
+source_configuration:
+  source_field: field_media_test_1
+  test_config_value: 'This is default value.'
+field_map: {  }
diff --git a/core/modules/media_library/tests/modules/media_library_test/media_library_test.info.yml b/core/modules/media_library/tests/modules/media_library_test/media_library_test.info.yml
new file mode 100644
index 0000000000..3ad1ae5f46
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/media_library_test.info.yml
@@ -0,0 +1,10 @@
+name: 'Media library test'
+type: module
+description: 'Test module for Media library.'
+package: Testing
+core: 8.x
+dependencies:
+  - drupal:media_library
+  - drupal:media_test_source
+  - drupal:menu_ui
+  - drupal:path
diff --git a/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
new file mode 100644
index 0000000000..d25b41bcd4
--- /dev/null
+++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
@@ -0,0 +1,102 @@
+<?php
+
+namespace Drupal\Tests\media_library\FunctionalJavascript;
+
+use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
+use Drupal\media\Entity\Media;
+
+/**
+ * Contains Media library integration tests.
+ *
+ * @group media_library
+ */
+class MediaLibraryTest extends JavascriptTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = ['block', 'media_library_test'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // Create a few example media items for use in selection.
+    $media = [
+      'type_one' => [
+        'media_1',
+        'media_2',
+      ],
+      'type_two' => [
+        'media_3',
+        'media_4',
+      ],
+    ];
+
+    foreach ($media as $type => $names) {
+      foreach ($names as $name) {
+        $entity = Media::create(['name' => $name, 'bundle' => $type]);
+        $source_field = $type === 'type_one' ? 'field_media_test' : 'field_media_test_1';
+        $entity->set($source_field, $this->randomString());
+        $entity->save();
+      }
+    }
+
+    // Create a user who can use the Media library.
+    $user = $this->drupalCreateUser([
+      'access administration pages',
+      'access media overview',
+      'create media',
+      'delete any media',
+      'view media',
+    ]);
+    $this->drupalLogin($user);
+    $this->drupalPlaceBlock('local_tasks_block');
+    $this->drupalPlaceBlock('local_actions_block');
+  }
+
+  /**
+   * Tests that the Media library's administration page works as expected.
+   */
+  public function testAdministrationPage() {
+    $assert_session = $this->assertSession();
+
+    // Visit the administration page.
+    $this->drupalGet('admin/content/media');
+
+    // Verify that the "Add media" link is present.
+    $assert_session->linkExists('Add media');
+
+    // Verify that media from two separate types is present.
+    $assert_session->pageTextContains('media_1');
+    $assert_session->pageTextContains('media_3');
+
+    // Test that users can filter by type.
+    $this->getSession()->getPage()->selectFieldOption('Media type', 'Type One');
+    $this->getSession()->getPage()->pressButton('Apply Filters');
+    $assert_session->assertWaitOnAjaxRequest();
+    $assert_session->pageTextContains('media_2');
+    $assert_session->pageTextNotContains('media_4');
+    $this->getSession()->getPage()->selectFieldOption('Media type', 'Type Two');
+    $this->getSession()->getPage()->pressButton('Apply Filters');
+    $assert_session->assertWaitOnAjaxRequest();
+    $assert_session->pageTextNotContains('media_2');
+    $assert_session->pageTextContains('media_4');
+
+    // Test that selecting elements as a part of bulk operations works.
+    $this->getSession()->getPage()->selectFieldOption('Media type', '- Any -');
+    $this->getSession()->getPage()->pressButton('Apply Filters');
+    $assert_session->assertWaitOnAjaxRequest();
+    // This tests that anchor tags clicked inside the preview are suppressed.
+    $this->getSession()->executeScript('jQuery(".click-to-select-trigger a")[0].click()');
+    $this->submitForm([], 'Apply to selected items');
+    $assert_session->pageTextContains('media_1');
+    $assert_session->pageTextNotContains('media_2');
+    $this->submitForm([], 'Delete');
+    $assert_session->pageTextNotContains('media_1');
+    $assert_session->pageTextContains('media_2');
+  }
+
+}
diff --git a/sites/README.txt b/sites/README.txt
old mode 100644
new mode 100755
diff --git a/sites/default/default.services.yml b/sites/default/default.services.yml
old mode 100644
new mode 100755
diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php
old mode 100644
new mode 100755
diff --git a/sites/development.services.yml b/sites/development.services.yml
old mode 100644
new mode 100755
diff --git a/sites/example.settings.local.php b/sites/example.settings.local.php
old mode 100644
new mode 100755
diff --git a/sites/example.sites.php b/sites/example.sites.php
old mode 100644
new mode 100755
