diff --git src/wp-admin/css/dashboard.css src/wp-admin/css/dashboard.css
index 72b0230..3ef5d82 100644
--- src/wp-admin/css/dashboard.css
+++ src/wp-admin/css/dashboard.css
@@ -518,6 +518,10 @@ form.initial-form.quickpress-open input#title {
 	resize: none;
 }
 
+#quick-press.is-saving .spinner {
+	visibility: inherit;
+}
+
 /* Dashboard Quick Draft - Drafts list */
 
 .js #dashboard_quick_press .drafts {
@@ -541,9 +545,43 @@ form.initial-form.quickpress-open input#title {
 	margin: 0 12px;
 }
 
+#dashboard_quick_press .drafts ul.is-placeholder li {
+	padding: 3px 0;
+	color: transparent;
+}
+
+@keyframes loading-fade {
+	0% { opacity: .5; }
+	50% { opacity: 1; }
+	100% { opacity: .5; }
+}
+
+#dashboard_quick_press .drafts ul.is-placeholder li:before,
+#dashboard_quick_press .drafts ul.is-placeholder li:after {
+	content: '';
+	display: block;
+	height: 13px;
+	background: #eee;
+	animation: loading-fade 1.6s ease-in-out infinite;
+}
+
+#dashboard_quick_press .drafts ul.is-placeholder li:before {
+	margin-bottom: 5px;
+	width: 40%;
+}
+
+#dashboard_quick_press .drafts ul.is-placeholder li:after {
+	width: 80%;
+}
+
 #dashboard_quick_press .drafts li {
 	margin-bottom: 1em;
 }
+
+#dashboard_quick_press .drafts li.is-new {
+	background-color: #fffbe5;
+}
+
 #dashboard_quick_press .drafts li time {
 	color: #72777c;
 }
diff --git src/wp-admin/includes/dashboard.php src/wp-admin/includes/dashboard.php
index aab5976..b472072 100644
--- src/wp-admin/includes/dashboard.php
+++ src/wp-admin/includes/dashboard.php
@@ -491,33 +491,26 @@ function wp_dashboard_quick_press( $error_msg = false ) {
 	$post_ID = (int) $post->ID;
 ?>
 
-	<form name="post" action="<?php echo esc_url( admin_url( 'post.php' ) ); ?>" method="post" id="quick-press" class="initial-form hide-if-no-js">
-
-		<?php if ( $error_msg ) : ?>
-		<div class="error"><?php echo $error_msg; ?></div>
-		<?php endif; ?>
+	<form name="post" method="post" id="quick-press" class="initial-form hide-if-no-js">
 
 		<div class="input-text-wrap" id="title-wrap">
-			<label class="screen-reader-text prompt" for="title" id="title-prompt-text">
+			<label class="prompt" for="title" id="title-prompt-text">
 
 				<?php
 				/** This filter is documented in wp-admin/edit-form-advanced.php */
 				echo apply_filters( 'enter_title_here', __( 'Title' ), $post );
 				?>
 			</label>
-			<input type="text" name="post_title" id="title" autocomplete="off" />
+			<input type="text" name="title" id="title" autocomplete="off" />
 		</div>
 
 		<div class="textarea-wrap" id="description-wrap">
-			<label class="screen-reader-text prompt" for="content" id="content-prompt-text"><?php _e( 'What&#8217;s on your mind?' ); ?></label>
+			<label class="prompt" for="content" id="content-prompt-text"><?php _e( 'What&#8217;s on your mind?' ); ?></label>
 			<textarea name="content" id="content" class="mceEditor" rows="3" cols="15" autocomplete="off"></textarea>
 		</div>
-
 		<p class="submit">
-			<input type="hidden" name="action" id="quickpost-action" value="post-quickdraft-save" />
-			<input type="hidden" name="post_ID" value="<?php echo $post_ID; ?>" />
-			<input type="hidden" name="post_type" value="post" />
-			<?php wp_nonce_field( 'add-post' ); ?>
+			<div class="error inline" style="display: none;"><p></p></div>
+			<div class="spinner no-float"></div>
 			<?php submit_button( __( 'Save Draft' ), 'primary', 'save', false, array( 'id' => 'save-post' ) ); ?>
 			<br class="clear" />
 		</p>
@@ -531,54 +524,21 @@ function wp_dashboard_quick_press( $error_msg = false ) {
  * Show recent drafts of the user on the dashboard.
  *
  * @since 2.7.0
- *
- * @param array $drafts
  */
-function wp_dashboard_recent_drafts( $drafts = false ) {
-	if ( ! $drafts ) {
-		$query_args = array(
-			'post_type'      => 'post',
-			'post_status'    => 'draft',
-			'author'         => get_current_user_id(),
-			'posts_per_page' => 4,
-			'orderby'        => 'modified',
-			'order'          => 'DESC'
-		);
-
-		/**
-		 * Filters the post query arguments for the 'Recent Drafts' dashboard widget.
-		 *
-		 * @since 4.4.0
-		 *
-		 * @param array $query_args The query arguments for the 'Recent Drafts' dashboard widget.
-		 */
-		$query_args = apply_filters( 'dashboard_recent_drafts_query_args', $query_args );
-
-		$drafts = get_posts( $query_args );
-		if ( ! $drafts ) {
-			return;
- 		}
- 	}
-
-	echo '<div class="drafts">';
-	if ( count( $drafts ) > 3 ) {
-		echo '<p class="view-all"><a href="' . esc_url( admin_url( 'edit.php?post_status=draft' ) ) . '" aria-label="' . __( 'View all drafts' ) . '">' . _x( 'View all', 'drafts' ) . "</a></p>\n";
- 	}
-	echo '<h2 class="hide-if-no-js">' . __( 'Drafts' ) . "</h2>\n<ul>";
-
-	$drafts = array_slice( $drafts, 0, 3 );
-	foreach ( $drafts as $draft ) {
-		$url = get_edit_post_link( $draft->ID );
-		$title = _draft_or_post_title( $draft->ID );
-		echo "<li>\n";
-		/* translators: %s: post title */
-		echo '<div class="draft-title"><a href="' . esc_url( $url ) . '" aria-label="' . esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $title ) ) . '">' . esc_html( $title ) . '</a>';
-		echo '<time datetime="' . get_the_time( 'c', $draft ) . '">' . get_the_time( __( 'F j, Y' ), $draft ) . '</time></div>';
-		if ( $the_content = wp_trim_words( $draft->post_content, 10 ) ) {
-			echo '<p>' . $the_content . '</p>';
- 		}
-		echo "</li>\n";
- 	}
+function wp_dashboard_recent_drafts() {
+	echo '<div id="quick-press-drafts" class="drafts">';
+	echo '<p class="view-all" style="display: none;"><a href="' . esc_url( admin_url( 'edit.php?post_status=draft' ) ) . '" aria-label="' . __( 'View all drafts' ) . '">' . _x( 'View all', 'drafts' ) . "</a></p>\n";
+	echo '<h2 class="hide-if-no-js">' . __( 'Drafts' ) . "</h2>\n";
+	echo '<script id="tmpl-item-quick-press-draft" type="text/template">';
+	/* translators: %s: post title */
+	echo '<div class="draft-title"><a href="post.php?post={{ data.id }}&action=edit" aria-label="' . esc_attr( __( 'Edit Post' ) ) . '">{{ data.title }}</a>';
+	echo '<time datetime="{{ data.date }}">{{ data.formattedDate }}</time></div>';
+	echo '{{{ data.formattedContent }}}';
+	echo '</script>';
+	echo '<ul class="drafts-list is-placeholder">';
+	for ( $i = 0; $i < 4; $i++ ) {
+		echo '<li><span class="screen-reader-text">' . esc_html( __( 'Loading…' ) ) . '</span></li>';
+	}
 	echo "</ul>\n</div>";
 }
 
diff --git src/wp-admin/js/dashboard.js src/wp-admin/js/dashboard.js
index fa100dd..7aa5c80 100644
--- src/wp-admin/js/dashboard.js
+++ src/wp-admin/js/dashboard.js
@@ -1,9 +1,9 @@
-/* global pagenow, ajaxurl, postboxes, wpActiveEditor:true */
-var ajaxWidgets, ajaxPopulateWidgets, quickPressLoad;
+/* global _, wp, quickPress, pagenow, ajaxurl, postboxes, wpActiveEditor:true */
+var ajaxWidgets, ajaxPopulateWidgets;
 
-jQuery(document).ready( function($) {
+jQuery( document ).ready( function( $ ) {
 	var welcomePanel = $( '#welcome-panel' ),
-		welcomePanelHide = $('#wp_welcome_panel-hide'),
+		welcomePanelHide = $( '#wp_welcome_panel-hide' ),
 		updateWelcomePanel;
 
 	updateWelcomePanel = function( visible ) {
@@ -11,39 +11,39 @@ jQuery(document).ready( function($) {
 			action: 'update-welcome-panel',
 			visible: visible,
 			welcomepanelnonce: $( '#welcomepanelnonce' ).val()
-		});
+		} );
 	};
 
-	if ( welcomePanel.hasClass('hidden') && welcomePanelHide.prop('checked') ) {
-		welcomePanel.removeClass('hidden');
+	if ( welcomePanel.hasClass( 'hidden' ) && welcomePanelHide.prop( 'checked' ) ) {
+		welcomePanel.removeClass( 'hidden' );
 	}
 
-	$('.welcome-panel-close, .welcome-panel-dismiss a', welcomePanel).click( function(e) {
+	$( '.welcome-panel-close, .welcome-panel-dismiss a', welcomePanel).click( function(e) {
 		e.preventDefault();
-		welcomePanel.addClass('hidden');
+		welcomePanel.addClass( 'hidden' );
 		updateWelcomePanel( 0 );
-		$('#wp_welcome_panel-hide').prop('checked', false);
-	});
+		$( '#wp_welcome_panel-hide' ).prop( 'checked', false);
+	} );
 
 	welcomePanelHide.click( function() {
-		welcomePanel.toggleClass('hidden', ! this.checked );
+		welcomePanel.toggleClass( 'hidden', ! this.checked );
 		updateWelcomePanel( this.checked ? 1 : 0 );
-	});
+	} );
 
 	// These widgets are sometimes populated via ajax
 	ajaxWidgets = ['dashboard_primary'];
 
 	ajaxPopulateWidgets = function(el) {
 		function show(i, id) {
-			var p, e = $('#' + id + ' div.inside:visible').find('.widget-loading');
+			var p, e = $( '#' + id + ' div.inside:visible' ).find( '.widget-loading' );
 			if ( e.length ) {
 				p = e.parent();
 				setTimeout( function(){
 					p.load( ajaxurl + '?action=dashboard-widgets&widget=' + id + '&pagenow=' + pagenow, '', function() {
-						p.hide().slideDown('normal', function(){
-							$(this).css('display', '');
-						});
-					});
+						p.hide().slideDown( 'normal', function(){
+							$(this).css( 'display', '' );
+						} );
+					} );
 				}, i * 500 );
 			}
 		}
@@ -61,68 +61,6 @@ jQuery(document).ready( function($) {
 
 	postboxes.add_postbox_toggles(pagenow, { pbshow: ajaxPopulateWidgets } );
 
-	/* QuickPress */
-	quickPressLoad = function() {
-		var act = $('#quickpost-action'), t;
-
-		$( '#quick-press .submit input[type="submit"], #quick-press .submit input[type="reset"]' ).prop( 'disabled' , false );
-
-		t = $('#quick-press').submit( function( e ) {
-			e.preventDefault();
-			$('#dashboard_quick_press #publishing-action .spinner').show();
-			$('#quick-press .submit input[type="submit"], #quick-press .submit input[type="reset"]').prop('disabled', true);
-
-			$.post( t.attr( 'action' ), t.serializeArray(), function( data ) {
-				// Replace the form, and prepend the published post.
-				$('#dashboard_quick_press .inside').html( data );
-				$('#quick-press').removeClass('initial-form');
-				quickPressLoad();
-				highlightLatestPost();
-				$('#title').focus();
-			});
-
-			function highlightLatestPost () {
-				var latestPost = $('.drafts ul li').first();
-				latestPost.css('background', '#fffbe5');
-				setTimeout(function () {
-					latestPost.css('background', 'none');
-				}, 1000);
-			}
-		} );
-
-		$('#publish').click( function() { act.val( 'post-quickpress-publish' ); } );
-
-		$('#title, #tags-input, #content').each( function() {
-			var input = $(this), prompt = $('#' + this.id + '-prompt-text');
-
-			if ( '' === this.value ) {
-				prompt.removeClass('screen-reader-text');
-			}
-
-			prompt.click( function() {
-				$(this).addClass('screen-reader-text');
-				input.focus();
-			});
-
-			input.blur( function() {
-				if ( '' === this.value ) {
-					prompt.removeClass('screen-reader-text');
-				}
-			});
-
-			input.focus( function() {
-				prompt.addClass('screen-reader-text');
-			});
-		});
-
-		$('#quick-press').on( 'click focusin', function() {
-			wpActiveEditor = 'content';
-		});
-
-		autoResizeTextarea();
-	};
-	quickPressLoad();
-
 	$( '.meta-box-sortables' ).sortable( 'option', 'containment', '#wpwrap' );
 
 	function autoResizeTextarea() {
@@ -131,10 +69,10 @@ jQuery(document).ready( function($) {
 		}
 
 		// Add a hidden div. We'll copy over the text from the textarea to measure its height.
-		$('body').append( '<div class="quick-draft-textarea-clone" style="display: none;"></div>' );
+		$( 'body' ).append( '<div class="quick-draft-textarea-clone" style="display: none;"></div>' );
 
-		var clone = $('.quick-draft-textarea-clone'),
-			editor = $('#content'),
+		var clone = $( '.quick-draft-textarea-clone' ),
+			editor = $( '#content' ),
 			editorHeight = editor.height(),
 			// 100px roughly accounts for browser chrome and allows the
 			// save draft button to show on-screen at the same time.
@@ -142,29 +80,29 @@ jQuery(document).ready( function($) {
 
 		// Match up textarea and clone div as much as possible.
 		// Padding cannot be reliably retrieved using shorthand in all browsers.
-		clone.css({
-			'font-family': editor.css('font-family'),
-			'font-size':   editor.css('font-size'),
-			'line-height': editor.css('line-height'),
-			'padding-bottom': editor.css('paddingBottom'),
-			'padding-left': editor.css('paddingLeft'),
-			'padding-right': editor.css('paddingRight'),
-			'padding-top': editor.css('paddingTop'),
+		clone.css( {
+			'font-family': editor.css( 'font-family' ),
+			'font-size':   editor.css( 'font-size' ),
+			'line-height': editor.css( 'line-height' ),
+			'padding-bottom': editor.css( 'paddingBottom' ),
+			'padding-left': editor.css( 'paddingLeft' ),
+			'padding-right': editor.css( 'paddingRight' ),
+			'padding-top': editor.css( 'paddingTop' ),
 			'white-space': 'pre-wrap',
 			'word-wrap': 'break-word',
 			'display': 'none'
-		});
+		} );
 
 		// propertychange is for IE < 9
-		editor.on('focus input propertychange', function() {
+		editor.on( 'focus input propertychange', function() {
 			var $this = $(this),
 				// &nbsp; is to ensure that the height of a final trailing newline is included.
 				textareaContent = $this.val() + '&nbsp;',
 				// 2px is for border-top & border-bottom
-				cloneHeight = clone.css('width', $this.css('width')).text(textareaContent).outerHeight() + 2;
+				cloneHeight = clone.css( 'width', $this.css( 'width' )).text(textareaContent).outerHeight() + 2;
 
 			// Default to having scrollbars
-			editor.css('overflow-y', 'auto');
+			editor.css( 'overflow-y', 'auto' );
 
 			// Only change the height if it has indeed changed and both heights are below the max.
 			if ( cloneHeight === editorHeight || ( cloneHeight >= editorMaxHeight && editorHeight >= editorMaxHeight ) ) {
@@ -180,10 +118,303 @@ jQuery(document).ready( function($) {
 			}
 
 			// No scrollbars as we change height, not for IE < 9
-			editor.css('overflow', 'hidden');
+			editor.css( 'overflow', 'hidden' );
 
-			$this.css('height', editorHeight + 'px');
-		});
+			$this.css( 'height', editorHeight + 'px' );
+		} );
 	}
 
+	autoResizeTextarea();
+
+} );
+
+wp.api.loadPromise.done( function() {
+	var $ = jQuery,
+		QuickPress = {},
+		draftsCollection;
+
+	/**
+	 * Models
+	 */
+
+	QuickPress.Models = {};
+
+	QuickPress.Models.Draft = wp.api.models.Post.extend( {
+		initialize: function( attributes ) {
+			if ( attributes ) {
+				this.set( this.normalizeAttributes( attributes ) );
+			}
+		},
+
+		parse: function( response ) {
+			return this.normalizeAttributes( response );
+		},
+
+		normalizeAttributes: function( attributes ) {
+			var date;
+
+			if ( ! attributes ) {
+				return attributes;
+			}
+
+			// Post entities from the REST API include the content and title in
+			// nested objects, but our new form model will assign as a string,
+			// so we normalize to simplify display logic
+
+			if ( 'object' === typeof attributes.content ) {
+				attributes.content = attributes.content.rendered;
+			}
+
+			if ( 'object' === typeof attributes.title ) {
+				attributes.title = attributes.title.rendered;
+			}
+
+			attributes.formattedContent = wp.formatting.trimWords( attributes.content, 10 );
+
+			// We can format dates using newer browser i18n features, but also
+			// provide a fallback to the not-as-nice Date#toLocaleDateString
+			date = new Date( attributes.modified_gmt );
+			if ( 'undefined' !== typeof Intl && Intl.DateTimeFormat ) {
+				attributes.formattedDate = new Intl.DateTimeFormat( undefined, {
+					timeZone: 'UTC',
+					month: 'long',
+					day: 'numeric',
+					year: 'numeric'
+				} ).format( date );
+			} else {
+				attributes.formattedDate = date.toLocaleDateString();
+			}
+
+			return attributes;
+		},
+
+		sync: function() {
+			// We explicitly set a date to the model before saving because the
+			// field is used for the formatte date display. The core behavior
+			// of saving drafts is such that a gmt date is not assigned until
+			// published. Without this, `modified_gmt` in the response is null
+			this.set( 'date_gmt', ( new Date() ).toISOString() );
+
+			return wp.api.models.Post.prototype.sync.apply( this, arguments );
+		},
+
+		validate: function( attributes ) {
+			if ( ! attributes.title && ! attributes.content ) {
+				return 'no-content';
+			}
+		}
+	} );
+
+	/**
+	 * Collections
+	 */
+
+	QuickPress.Collections = {};
+
+	QuickPress.Collections.Drafts = wp.api.collections.Posts.extend( {
+		model: QuickPress.Models.Draft,
+
+		comparator: function( a, b ) {
+			// Sort by date descending, date is an ISO8601 string and can be
+			// compared lexicographically
+			return a.get( 'date' ) < b.get( 'date' );
+		}
+	} );
+
+	/**
+	 * Collections
+	 */
+
+	QuickPress.Views = {};
+
+	QuickPress.Views.Form = wp.Backbone.View.extend( {
+		events: {
+			'click :input': 'hidePromptAndFocus',
+			'focus :input': 'hidePrompt',
+			'blur :input': 'showPrompt',
+			reset: 'showAllPrompts',
+			click: 'setActiveEditor',
+			focusin: 'setActiveEditor',
+			submit: 'submit'
+		},
+
+		initialize: function() {
+			this.showAllPrompts();
+
+			this.listenTo( this.model, 'invalid', this.render );
+			this.listenTo( this.model, 'error', this.showSyncError );
+		},
+
+		togglePrompt: function( element, visible ) {
+			var $input = $( element ),
+				hasContent = $input.val().length > 0;
+
+			$( element ).siblings( '.prompt' ).toggleClass( 'screen-reader-text', ! visible || hasContent );
+		},
+
+		showAllPrompts: function() {
+			this.$el.find( ':input' ).each( _.bind( function( i, input ) {
+				// Prompt toggling must be deferred because the reset event is
+				// fired before the input values have been cleared
+				_.defer( _.bind( this.togglePrompt, this, input, true ) );
+			}, this ) );
+		},
+
+		showPrompt: function( event ) {
+			this.togglePrompt( event.target, true );
+		},
+
+		hidePrompt: function( event ) {
+			this.togglePrompt( event.target, false );
+		},
+
+		hidePromptAndFocus: function( event ) {
+			this.togglePrompt( event.target, false );
+			$( ':input', event.target ).focus();
+		},
+
+		setActiveEditor: function() {
+			wpActiveEditor = 'content';
+		},
+
+		showSyncError: function() {
+			this.syncError = true;
+			this.render();
+		},
+
+		submit: function( event ) {
+			var values;
+
+			delete this.syncError;
+			event.preventDefault();
+
+			// jQuery's serializeArray returns an array of field tuples, which
+			// we need to transform into an object before sending to API
+			values = this.$el.serializeArray().reduce( function( memo, field ) {
+				memo[ field.name ] = field.value;
+				return memo;
+			}, {} );
+
+			// Ensure that by setting these fields on model that it is valid
+			// before proceeding with save
+			this.model.set( values );
+			if ( ! this.model.isValid() ) {
+				return;
+			}
+
+			// Show a spinner during the callback.
+			this.$el.addClass( 'is-saving' );
+
+			this.model.save()
+				.always( _.bind( function() {
+					this.$el.removeClass( 'is-saving' );
+				}, this ) )
+				.success( _.bind( function() {
+					this.collection.add( this.model );
+					this.model = new QuickPress.Models.Draft();
+					this.el.reset();
+				}, this ) );
+		},
+
+		render: function() {
+			var $error = this.$el.find( '.error' ),
+				errorText;
+
+			if ( this.model.validationError ) {
+				// Error via submission validation
+				errorText = quickPress.l10n[ this.model.validationError ];
+			} else if ( this.syncError ) {
+				// Error via API save failure
+				errorText = quickPress.l10n.error;
+			}
+
+			// Error notice is only visible if error text determined
+			$error.toggle( !! errorText );
+			if ( errorText ) {
+				$error.html( $( '<p />', { text: errorText } ) );
+			}
+		}
+	} );
+
+	QuickPress.Views.DraftList = wp.Backbone.View.extend( {
+		initialize: function() {
+			this.listenTo( this.collection, 'sync', this.onDraftsLoaded );
+		},
+
+		onDraftsLoaded: function() {
+			this.listenTo( this.collection, 'add', this.renderNew );
+			this.render();
+		},
+
+		renderNew: function() {
+			// Display highlight effect to first (added) item for one second
+			var $newEl = this.render().$el.find( 'li:first' ).addClass( 'is-new' );
+			setTimeout( function() {
+				$newEl.removeClass( 'is-new' );
+			}, 1000 );
+		},
+
+		render: function() {
+			// Though we request only four drafts initially, since more will be
+			// added through the form, render only the first four sorted
+			var slicedCollection = this.collection.slice( 0, 4 );
+
+			// Hide drafts list if no drafts exist
+			this.$el.toggle( this.collection.length > 0 );
+
+			// "View All" link is visible if 4 or more drafts, since we only
+			// show a maximum of 4 drafts in the list
+			this.$el.find( '.view-all' ).toggle( slicedCollection.length > 3 );
+
+			// If after drafts load, this could be the first render, so remove
+			// placeholder effect and render the first four drafts
+			this.$el.find( '.drafts-list' )
+				.removeClass( 'is-placeholder' )
+				.html( _.map( slicedCollection, function( draft ) {
+					return new QuickPress.Views.DraftListItem( {
+						model: draft
+					} ).render().el;
+				} ) );
+
+			return this;
+		}
+	} );
+
+	QuickPress.Views.DraftListItem = wp.Backbone.View.extend( {
+		tagName: 'li',
+
+		template: wp.template( 'item-quick-press-draft' ),
+
+		render: function() {
+			this.$el.html( this.template( this.model.attributes ) );
+
+			return this;
+		}
+	} );
+
+	/**
+	 * Initialize
+	 */
+
+	// Fetch drafts
+	draftsCollection = new QuickPress.Collections.Drafts();
+	draftsCollection.fetch( {
+		data: {
+			status: 'draft',
+			author: quickPress.currentUserId,
+			per_page: 4
+		}
+	} );
+
+	// Drafts list is initialized but not rendered until drafts load
+	new QuickPress.Views.DraftList( {
+		el: '#quick-press-drafts',
+		collection: draftsCollection
+	} );
+
+	new QuickPress.Views.Form( {
+		el: '#quick-press',
+		model: new QuickPress.Models.Draft(),
+		collection: draftsCollection
+	} ).render();
 } );
diff --git src/wp-admin/post.php src/wp-admin/post.php
index 437d1bd..df78352 100644
--- src/wp-admin/post.php
+++ src/wp-admin/post.php
@@ -60,34 +60,6 @@ if ( ! $sendback ||
 }
 
 switch($action) {
-case 'post-quickdraft-save':
-	// Check nonce and capabilities
-	$nonce = $_REQUEST['_wpnonce'];
-	$error_msg = false;
-
-	// For output of the quickdraft dashboard widget
-	require_once ABSPATH . 'wp-admin/includes/dashboard.php';
-
-	if ( ! wp_verify_nonce( $nonce, 'add-post' ) )
-		$error_msg = __( 'Unable to submit this form, please refresh and try again.' );
-
-	if ( ! current_user_can( get_post_type_object( 'post' )->cap->create_posts ) ) {
-		exit;
-	}
-
-	if ( $error_msg )
-		return wp_dashboard_quick_press( $error_msg );
-
-	$post = get_post( $_REQUEST['post_ID'] );
-	check_admin_referer( 'add-' . $post->post_type );
-
-	$_POST['comment_status'] = get_default_comment_status( $post->post_type );
-	$_POST['ping_status']    = get_default_comment_status( $post->post_type, 'pingback' );
-
-	edit_post();
-	wp_dashboard_quick_press();
-	exit;
-
 case 'postajaxpost':
 case 'post':
 	check_admin_referer( 'add-' . $post_type );
diff --git src/wp-includes/js/wp-util.js src/wp-includes/js/wp-util.js
index 527441d..79ab07e 100644
--- src/wp-includes/js/wp-util.js
+++ src/wp-includes/js/wp-util.js
@@ -121,4 +121,50 @@ window.wp = window.wp || {};
 		}
 	};
 
+	// wp.formatting
+	// ------
+	//
+	// Tools for formatting strings
+	wp.formatting = {
+		settings: settings.formatting || {},
+
+		/**
+		 * Trims text to a certain number of words.
+		 *
+		 * @see wp_trim_words
+		 *
+		 * @param  {string}  text     Text to trim.
+		 * @param  {?number} numWords Number of words (default: 55).
+		 * @param  {?string} more     What to append if text needs to be trimmed (default: '…').
+		 * @return {string}           Trimmed text.
+		 */
+		trimWords: function( text, numWords, more ) {
+			var words, separator;
+
+			if ( 'undefined' === typeof numWords ) {
+				numWords = 55;
+			}
+
+			if ( 'undefined' === typeof more ) {
+				more = wp.formatting.settings.trimWordsMore;
+			}
+
+			text = text.replace( /[\n\r\t ]+/g, ' ' ).replace( /^ | $/g, '' );
+
+			if ( wp.formatting.settings.trimWordsByCharacter ) {
+				separator = '';
+			} else {
+				separator = ' ';
+			}
+
+			words = text.split( separator );
+
+			if ( words.length <= numWords ) {
+				return words.join( separator );
+			}
+
+			return words.slice( 0, numWords ).join( separator ) + more;
+		}
+	};
+
 }(jQuery));
diff --git src/wp-includes/script-loader.php src/wp-includes/script-loader.php
index 143bfa1..95bed93 100644
--- src/wp-includes/script-loader.php
+++ src/wp-includes/script-loader.php
@@ -333,6 +333,15 @@ function wp_default_scripts( &$scripts ) {
 		'ajax' => array(
 			'url' => admin_url( 'admin-ajax.php', 'relative' ),
 		),
+		'formatting' => array(
+			'trimWordsMore'  => __( '&hellip;' ),
+			/*
+			 * translators: If your word count is based on single characters (e.g. East Asian characters),
+			 * enter 'characters_excluding_spaces' or 'characters_including_spaces'. Otherwise, enter 'words'.
+			 * Do not translate into your own language.
+			 */
+			'trimWordsByCharacter' => strpos( _x( 'words', 'Word count type. Do not translate!' ), 'characters' ) === 0 && preg_match( '/^utf\-?8$/i', get_option( 'blog_charset' ) ),
+		),
 	) );
 
 	$scripts->add( 'wp-backbone', "/wp-includes/js/wp-backbone$suffix.js", array('backbone', 'wp-util'), false, 1 );
@@ -716,7 +725,14 @@ function wp_default_scripts( &$scripts ) {
 			'current' => __( 'Current Color' ),
 		) );
 
-		$scripts->add( 'dashboard', "/wp-admin/js/dashboard$suffix.js", array( 'jquery', 'admin-comments', 'postbox' ), false, 1 );
+		$scripts->add( 'dashboard', "/wp-admin/js/dashboard$suffix.js", array( 'jquery', 'admin-comments', 'postbox', 'wp-api', 'wp-backbone' ), false, 1 );
+		did_action( 'init' ) && $scripts->localize( 'dashboard', 'quickPress', array(
+			'currentUserId' => get_current_user_id(),
+			'l10n' => array(
+				'no-content' => __( 'Post content cannot be empty.' ),
+				'error'      => __( 'An error has occurred. Please reload the page and try again.' )
+			)
+		) );
 
 		$scripts->add( 'list-revisions', "/wp-includes/js/wp-list-revisions$suffix.js" );
 
