Index: src/wp-includes/css/media-views.css
===================================================================
--- src/wp-includes/css/media-views.css	(revision 29483)
+++ src/wp-includes/css/media-views.css	(working copy)
@@ -729,8 +729,19 @@
 	-webkit-box-sizing: border-box;
 	-moz-box-sizing: border-box;
 	box-sizing: border-box;
+	opacity: 1;
 }
 
+.media-frame.mode-select .attachment {
+	opacity: 0.65;
+	-webkit-transition: opacity 250ms;
+	transition: opacity 250ms;
+}
+
+.media-frame.mode-select .attachment.selected {
+	opacity: 1;
+}
+
 .attachment:focus {
 	-webkit-box-shadow:
 		inset 0 0 0 5px #fff,
@@ -741,6 +752,15 @@
 	outline: none;
 }
 
+.media-frame.mode-grid .attachment:focus {
+	-webkit-box-shadow:
+		inset 0 0 0 6px #f1f1f1,
+		inset 0 0 1px 7px #5b9dd9;
+	box-shadow:
+		inset 0 0 0 6px #f1f1f1,
+		inset 0 0 1px 7px #5b9dd9;
+}
+
 .selected.attachment {
 	-webkit-box-shadow:
 		inset 0 0 0 5px #fff,
@@ -750,6 +770,15 @@
 		inset 0 0 0 7px #ccc;
 }
 
+.media-frame.mode-grid .selected.attachment {
+	-webkit-box-shadow:
+		inset 0 0 0 6px #f1f1f1,
+		inset 0 0 0 7px #ccc;
+	box-shadow:
+		inset 0 0 0 6px #f1f1f1,
+		inset 0 0 0 7px #ccc;
+}
+
 .attachment-preview {
 	position: relative;
 	-webkit-box-shadow:
@@ -922,8 +951,7 @@
 }
 
 .selected.attachment:focus,
-.attachment.details,
-.media-frame.mode-grid .selected.attachment {
+.attachment.details {
 	-webkit-box-shadow:
 		inset 0 0 0 3px #fff,
 		inset 0 0 0 7px #1e8cbe;
@@ -932,6 +960,15 @@
 		inset 0 0 0 7px #1e8cbe;
 }
 
+.media-frame.mode-grid .selected.attachment:focus {
+	-webkit-box-shadow:
+		inset 0 0 0 3px #f1f1f1,
+		inset 0 0 0 7px #1e8cbe;
+	box-shadow:
+		inset 0 0 0 3px #f1f1f1,
+		inset 0 0 0 7px #1e8cbe;
+}
+
 .attachment.details .check,
 .attachment.selected .check:focus,
 .media-frame.mode-grid .attachment.selected .check {
@@ -944,14 +981,6 @@
 		0 0 0 2px #1e8cbe;
 }
 
-.media-frame.mode-grid .attachment .check {
-	display: block;
-}
-
-.media-frame.mode-grid .attachment .check div {
-	background-position: 21px 0;
-}
-
 .attachment.details .check div,
 .media-frame.mode-grid .attachment.selected .check div {
 	background-position: -21px 0;
@@ -997,7 +1026,7 @@
 .attachments-browser .media-toolbar-primary > .media-button-group,
 .attachments-browser .media-toolbar-secondary > .media-button,
 .attachments-browser .media-toolbar-secondary > .media-button-group {
-	margin-top: 10px;
+	margin: 11px 0;
 }
 
 .attachments-browser .attachments,
@@ -2453,7 +2482,6 @@
 
 /* Regions we don't use at all */
 .media-frame.mode-grid .media-frame-title,
-.media-frame.mode-grid .media-frame-toolbar,
 .media-frame.mode-grid .media-frame-router,
 .media-frame.mode-grid .media-frame-menu {
 	display: none;
@@ -2488,6 +2516,10 @@
 	padding: 2px;
 }
 
+.media-frame.mode-select .attachments {
+	padding: 2px;
+}
+
 /**
  * Copied styles from the Add theme toolbar.
  *
@@ -2511,6 +2543,14 @@
 	border: none;
 }
 
+.media-frame.mode-select .attachments-browser .media-toolbar.fixed {
+	position: fixed;
+	top: 28px;
+	left: 182px;
+	right: 20px;
+	width: auto;
+}
+
 .media-frame.mode-grid input[type="search"] {
 	margin: 1px;
 	padding: 3px 5px;
@@ -2539,6 +2579,10 @@
 	margin-top: 15px;
 }
 
+.attachments-browser .media-toolbar-secondary > .select-mode-toggle-button {
+	margin-right: 10px;
+}
+
 .media-frame.mode-grid .attachments-browser {
 	padding: 0;
 }
Index: src/wp-includes/js/media-grid.js
===================================================================
--- src/wp-includes/js/media-grid.js	(revision 29483)
+++ src/wp-includes/js/media-grid.js	(working copy)
@@ -62,10 +62,13 @@
 				multiple:  'add',
 				state:     'library',
 				uploader:  true,
-				mode:      [ 'grid' ]
+				mode:      [ 'grid', 'edit' ]
 			});
 
-			$(document).on( 'click', '.add-new-h2', _.bind( this.addNewClickHandler, this ) );
+			this.$window = $( window );
+			this.$adminBar = $( '#wpadminbar' );
+			this.$window.on( 'scroll', _.debounce( _.bind( this.fixPosition, this ), 15 ) );
+			$( document ).on( 'click', '.add-new-h2', _.bind( this.addNewClickHandler, this ) );
 
 			// Ensure core and media grid view UI is enabled.
 			this.$el.addClass('wp-core-ui');
@@ -96,6 +99,8 @@
 			// Call 'initialize' directly on the parent class.
 			media.view.MediaFrame.prototype.initialize.apply( this, arguments );
 
+			this.on( 'all', function () { console.log( arguments ); } );
+
 			// Append the frame view directly the supplied container.
 			this.$el.appendTo( this.options.container );
 
@@ -130,6 +135,7 @@
 					multiple:           options.multiple,
 					title:              options.title,
 					content:            'browse',
+					toolbar:            'select',
 					contentUserSetting: false,
 					filterable:         'all'
 				})
@@ -146,6 +152,21 @@
 			this.on( 'edit:attachment', this.openEditAttachmentModal, this );
 		},
 
+		fixPosition: function() {
+			var $browser;
+			if ( ! this.isModeActive( 'select' ) ) {
+				return;
+			}
+
+			$browser = this.$('.attachments-browser');
+
+			if ( $browser.offset().top < this.$window.scrollTop() + this.$adminBar.height() ) {
+				$browser.find('.media-toolbar').addClass( 'fixed' );
+			} else {
+				$browser.find('.media-toolbar').removeClass( 'fixed' );
+			}
+		},
+
 		/**
 		 * Click handler for the `Add New` button.
 		 */
@@ -542,130 +563,64 @@
 		}
 	});
 
-	/**
-	 * Controller for bulk selection.
-	 */
-	media.view.BulkSelection = media.View.extend({
-		className: 'bulk-select',
-
+	media.view.SelectModeToggleButton = media.view.Button.extend({
 		initialize: function() {
-			this.model = new Backbone.Model({
-				currentAction: ''
+			media.view.Button.prototype.initialize.apply( this, arguments );
+			this.listenTo( this.controller, 'select:activate select:deactivate', this.toggleBulkEditHandler );
+		},
 
-			});
+		click: function() {
+			media.view.Button.prototype.click.apply( this, arguments );
+			if ( this.controller.isModeActive( 'select' ) ) {
+				this.controller.deactivateMode( 'select' ).activateMode( 'edit' );
+			} else {
+				this.controller.deactivateMode( 'edit' ).activateMode( 'select' );
+			}
+		},
 
-			this.views.add( new media.view.Label({
-				value: l10n.bulkActionsLabel,
-				attributes: {
-					'for': 'bulk-select-dropdown'
-				}
-			}) );
+		render: function() {
+			media.view.Button.prototype.render.apply( this, arguments );
+			this.$el.addClass( 'select-mode-toggle-button' );
+			return this;
+		},
 
-			this.views.add(
-				new media.view.BulkSelectionActionDropdown({
-					controller: this
-				})
-			);
+		toggleBulkEditHandler: function() {
+			var toolbar = this.controller.content.get().toolbar, children;
 
-			this.views.add(
-				new media.view.BulkSelectionActionButton({
-					disabled:   true,
-					text:       l10n.apply,
-					controller: this
-				})
-			);
+			children = toolbar.$( '.media-toolbar-secondary > *, .media-toolbar-primary > *');
+
+			if ( this.controller.isModeActive( 'select' ) ) {
+				this.model.set( 'text', l10n.cancelSelection );
+				children.not( '.delete-selected-button' ).hide();
+				toolbar.$( '.select-mode-toggle-button' ).show();
+				toolbar.$( '.delete-selected-button' ).removeClass( 'hidden' );
+			} else {
+				this.model.set( 'text', l10n.bulkSelect );
+				toolbar.$( '.delete-selected-button' ).addClass( 'hidden' );
+				children.not( '.spinner, .delete-selected-button' ).show();
+				this.controller.state().get( 'selection' ).reset();
+			}
 		}
 	});
 
-	/**
-	 * Bulk Selection dropdown view.
-	 *
-	 * @constructor
-	 * @augments wp.media.View
-	 * @augments wp.Backbone.View
-	 * @augments Backbone.View
-	 */
-	media.view.BulkSelectionActionDropdown = media.View.extend({
-		tagName: 'select',
-		id:      'bulk-select-dropdown',
-
+	media.view.DeleteSelectedButton = media.view.Button.extend({
 		initialize: function() {
 			media.view.Button.prototype.initialize.apply( this, arguments );
-			this.listenTo( this.controller.controller.state().get( 'selection' ), 'add remove reset', _.bind( this.enabled, this ) );
-			this.$el.append( $('<option></option>').val( '' ).html( l10n.bulkActions ) )
-				.append( $('<option></option>').val( 'delete' ).html( l10n.deletePermanently ) );
-			this.$el.prop( 'disabled', true );
-			this.$el.on( 'change', _.bind( this.changeHandler, this ) );
+			this.listenTo( this.controller, 'selection:toggle', this.toggleDisabled );
 		},
 
-		/**
-		 * Change handler for the dropdown.
-		 *
-		 * Sets the bulk selection controller's currentAction.
-		 */
-		changeHandler: function() {
-			this.controller.model.set( { 'currentAction': this.$el.val() } );
+		toggleDisabled: function() {
+			this.$el.attr( 'disabled', ! this.controller.state().get( 'selection' ).length );
 		},
 
-		/**
-		 * Enable or disable the dropdown if attachments have been selected.
-		 */
-		enabled: function() {
-			var disabled = ! this.controller.controller.state().get('selection').length;
-			this.$el.prop( 'disabled', disabled );
+		render: function() {
+			media.view.Button.prototype.render.apply( this, arguments );
+			this.$el.addClass( 'delete-selected-button hidden' );
+			return this;
 		}
 	});
 
 	/**
-	 * Bulk Selection dropdown view.
-	 *
-	 * @constructor
-	 *
-	 * @augments wp.media.view.Button
-	 * @augments wp.media.View
-	 * @augments wp.Backbone.View
-	 * @augments Backbone.View
-	 */
-	media.view.BulkSelectionActionButton = media.view.Button.extend({
-		tagName: 'button',
-
-		initialize: function() {
-			media.view.Button.prototype.initialize.apply( this, arguments );
-
-			this.listenTo( this.controller.model, 'change', this.enabled, this );
-			this.listenTo( this.controller.controller.state().get( 'selection' ), 'add remove reset', _.bind( this.enabled, this ) );
-		},
-		/**
-		 * Button click handler.
-		 */
-		click: function() {
-			var selection = this.controller.controller.state().get('selection');
-			media.view.Button.prototype.click.apply( this, arguments );
-
-			if ( 'delete' === this.controller.model.get( 'currentAction' ) ) {
-				// Currently assumes delete is the only action
-				if ( confirm( l10n.warnBulkDelete ) ) {
-					while ( selection.length > 0 ) {
-						selection.at(0).destroy();
-					}
-				}
-			}
-
-			this.enabled();
-		},
-		/**
-		 * Enable or disable the button depending if a bulk action is selected
-		 * in the bulk select dropdown, and if attachments have been selected.
-		 */
-		enabled: function() {
-			var currentAction = this.controller.model.get( 'currentAction' ),
-				selection = this.controller.controller.state().get('selection'),
-				disabled = ! currentAction || ! selection.length;
-			this.$el.prop( 'disabled', disabled );
-		}
-	});
-
-	/**
 	 * A filter dropdown for month/dates.
 	 */
 	media.view.DateFilter = media.view.AttachmentFilters.extend({
Index: src/wp-includes/js/media-views.js
===================================================================
--- src/wp-includes/js/media-views.js	(revision 29483)
+++ src/wp-includes/js/media-views.js	(working copy)
@@ -1792,7 +1792,7 @@
 		deactivateMode: function( mode ) {
 			// Bail if the mode isn't active.
 			if ( ! this.isModeActive( mode ) ) {
-				return;
+				return this;
 			}
 			this.activeModes.remove( this.activeModes.where( { id: mode } ) );
 			this.$el.removeClass( 'mode-' + mode );
@@ -4821,12 +4821,18 @@
 
 			// In the grid view, bubble up an edit:attachment event to the controller.
 			if ( this.controller.isModeActive( 'grid' ) ) {
-				// Pass the current target to restore focus when closing
-				this.controller.trigger( 'edit:attachment', this.model, event.currentTarget );
+				if ( this.controller.isModeActive( 'edit' ) ) {
+					// Pass the current target to restore focus when closing
+					this.controller.trigger( 'edit:attachment', this.model, event.currentTarget );
 
-				// Don't scroll the view and don't attempt to submit anything.
-				event.stopPropagation();
-				return;
+					// Don't scroll the view and don't attempt to submit anything.
+					event.stopPropagation();
+					return;
+				}
+
+				if ( this.controller.isModeActive( 'select' ) ) {
+					method = 'toggle';
+				}
 			}
 
 			if ( event.shiftKey ) {
@@ -4839,6 +4845,8 @@
 				method: method
 			});
 
+			this.controller.trigger( 'selection:toggle' );
+
 			// Don't scroll the view and don't attempt to submit anything.
 			event.stopPropagation();
 		},
@@ -5784,12 +5792,6 @@
 					priority: -90
 				}).render() );
 
-				// BulkSelection is a <div> with subviews, including screen reader text
-				this.toolbar.set( 'bulkSelection', new media.view.BulkSelection({
-					controller: this.controller,
-					priority: -70
-				}).render() );
-
 				// DateFilter is a <select>, screen reader text needs to be rendered before
 				this.toolbar.set( 'dateFilterLabel', new media.view.Label({
 					value: l10n.filterByDate,
@@ -5803,6 +5805,26 @@
 					model:      this.collection.props,
 					priority: -75
 				}).render() );
+
+				// BulkSelection is a <div> with subviews, including screen reader text
+				this.toolbar.set( 'selectModeToggleButton', new media.view.SelectModeToggleButton({
+					text: l10n.bulkSelect,
+					controller: this.controller,
+					priority: -70
+				}).render() );
+
+				this.toolbar.set( 'deleteSelectedButton', new media.view.DeleteSelectedButton({
+					style: 'primary',
+					disabled: true,
+					text:  l10n.deleteSelected,
+					controller: this.controller,
+					priority: -60,
+					click: function() {
+						while ( this.controller.state().get( 'selection' ).length > 0 ) {
+							this.controller.state().get( 'selection' ).at( 0 ).destroy();
+						}
+					}
+				}).render() );
 			}
 
 			this.toolbar.set( 'spinner', new media.view.Spinner({
Index: src/wp-includes/media.php
===================================================================
--- src/wp-includes/media.php	(revision 29483)
+++ src/wp-includes/media.php	(working copy)
@@ -2936,6 +2936,9 @@
 		'warnBulkDelete'         => __( "You are about to permanently delete these items.\n  'Cancel' to stop, 'OK' to delete." ),
 		'bulkActions'            => __( 'Bulk Actions' ),
 		'bulkActionsLabel'       => __( 'Select bulk action' ),
+		'bulkSelect'             => __( 'Bulk Select' ),
+		'cancelSelection'        => __( 'Cancel Selection' ),
+		'deleteSelected'         => __( 'Delete Selected' ),
 		'deletePermanently'      => __( 'Delete Permanently' ),
 		'apply'                  => __( 'Apply' ),
 		'filterByDate'           => __( 'Filter by date' ),
