diff --git a/components-chromium/iron-list/iron-list.js b/components-chromium/iron-list/iron-list.js
index 67ec9a735773d..ad8e118645b56 100644
--- a/components-chromium/iron-list/iron-list.js
+++ b/components-chromium/iron-list/iron-list.js
@@ -207,19 +207,6 @@ to previous and next items in the list:
 </iron-list>
 ```
 
-### Styling
-
-You can use the `--iron-list-items-container` mixin to style the container of
-items:
-
-```css
-iron-list {
- --iron-list-items-container: {
-    margin: auto;
-  };
-}
-```
-
 ### Resizing
 
 `iron-list` lays out the items when it receives a notification via the
@@ -267,7 +254,6 @@ Polymer({
       }
 
       #items {
-        @apply --iron-list-items-container;
         position: relative;
       }
 
@@ -376,7 +362,15 @@ Polymer({
      * there's some offset between the scrolling element and the list. For
      * example: a header is placed above the list.
      */
-    scrollOffset: {type: Number, value: 0}
+    scrollOffset: {type: Number, value: 0},
+
+    /**
+     * If set to true, focus on an element will be preserved after rerender.
+     */
+    preserveFocus: {
+      type: Boolean,
+      value: false
+    }
   },
 
   observers: [
@@ -1066,11 +1060,53 @@ Polymer({
     newGrid && this._updateGridMetrics();
   },
 
+  /**
+   * Finds and returns the focused element (both within self and children's
+   * Shadow DOM).
+   * @return {?HTMLElement}
+   */
+  _getFocusedElement: function() {
+    function doSearch(node, query) {
+      let result = null;
+      let type = node.nodeType;
+      if (type == Node.ELEMENT_NODE || type == Node.DOCUMENT_FRAGMENT_NODE)
+        result = node.querySelector(query);
+      if (result)
+        return result;
+
+      let child = node.firstChild;
+      while (child !== null && result === null) {
+        result = doSearch(child, query);
+        child = child.nextSibling;
+      }
+      if (result)
+        return result;
+
+      const shadowRoot = node.shadowRoot;
+      return shadowRoot ? doSearch(shadowRoot, query) : null;
+    }
+
+    // Find out if any of the items are focused first, and only search
+    // recursively in the item that contains focus, to avoid a slow
+    // search of the entire list.
+    const focusWithin = doSearch(this, ':focus-within');
+    return focusWithin ? doSearch(focusWithin, ':focus') : null;
+  },
+
   /**
    * Called when the items have changed. That is, reassignments
    * to `items`, splices or updates to a single item.
    */
   _itemsChanged: function(change) {
+    var rendering = /^items(\.splices){0,1}$/.test(change.path);
+    var lastFocusedIndex, focusedElement;
+    if (rendering && this.preserveFocus) {
+      lastFocusedIndex = this._focusedVirtualIndex;
+      focusedElement = this._getFocusedElement();
+    }
+
+    var preservingFocus = rendering && this.preserveFocus && focusedElement;
+
     if (change.path === 'items') {
       this._virtualStart = 0;
       this._physicalTop = 0;
@@ -1082,7 +1118,7 @@ Polymer({
       this._physicalItems = this._physicalItems || [];
       this._physicalSizes = this._physicalSizes || [];
       this._physicalStart = 0;
-      if (this._scrollTop > this._scrollOffset) {
+      if (this._scrollTop > this._scrollOffset && !preservingFocus) {
         this._resetScrollPosition(0);
       }
       this._removeFocusedItem();
@@ -1114,6 +1150,17 @@ Polymer({
     } else if (change.path !== 'items.length') {
       this._forwardItemPath(change.path, change.value);
     }
+
+    // If the list was in focus when updated, preserve the focus on item.
+    if (preservingFocus) {
+      flush();
+      focusedElement.blur();  // paper- elements breaks when focused twice.
+      this._focusPhysicalItem(
+          Math.min(this.items.length - 1, lastFocusedIndex));
+      if (!this._isIndexVisible(this._focusedVirtualIndex)) {
+        this.scrollToIndex(this._focusedVirtualIndex);
+      }
+    }
   },
 
   _forwardItemPath: function(path, value) {
@@ -1851,13 +1898,7 @@ Polymer({
     if (!targetModel) {
       return;
     }
-    if (focusedModel === targetModel) {
-      // If the user focused the same item, then bring it into view if it's not
-      // visible.
-      if (!this._isIndexVisible(fidx)) {
-        this.scrollToIndex(fidx);
-      }
-    } else {
+    if (focusedModel !== targetModel) {
       this._restoreFocusedItem();
       // Restore tabIndex for the currently focused item.
       if (focusedModel) {
