Convert legacy Polyemer elements to class-based

This commit converts almost all Polymer elements from Polymer-function
based components to class-based components. There are few files which
should be converted manually after this commit.

Change-Id: I9e597e79053e0a6b5d5c0f1b54676d11b9d81db7
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
index 01b7618..2ce0d7d 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
@@ -192,9 +192,19 @@
   const AWAIT_CHANGE_ATTEMPTS = 5;
   const AWAIT_CHANGE_TIMEOUT_MS = 1000;
 
-  Polymer({
-    is: 'gr-change-actions',
-
+  /**
+    * @appliesMixin Gerrit.FireMixin
+    * @appliesMixin Gerrit.PatchSetMixin
+    * @appliesMixin Gerrit.RESTClientMixin
+    */
+  class GrChangeActions extends Polymer.mixinBehaviors( [
+    Gerrit.FireBehavior,
+    Gerrit.PatchSetBehavior,
+    Gerrit.RESTClientBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-change-actions'; }
     /**
      * Fired when the change should be reloaded.
      *
@@ -219,7 +229,15 @@
      * @event show-error
      */
 
-    properties: {
+    constructor() {
+      super();
+      this.ActionType = ActionType;
+      this.ChangeActions = ChangeActions;
+      this.RevisionActions = RevisionActions;
+    }
+
+    static get properties() {
+      return {
       /**
        * @type {{
        *    _number: number,
@@ -229,217 +247,214 @@
        *    subject: string,
        *  }}
        */
-      change: Object,
-      actions: {
-        type: Object,
-        value() { return {}; },
-      },
-      primaryActionKeys: {
-        type: Array,
-        value() {
-          return [
-            RevisionActions.SUBMIT,
-          ];
+        change: Object,
+        actions: {
+          type: Object,
+          value() { return {}; },
         },
-      },
-      disableEdit: {
-        type: Boolean,
-        value: false,
-      },
-      _hasKnownChainState: {
-        type: Boolean,
-        value: false,
-      },
-      _hideQuickApproveAction: {
-        type: Boolean,
-        value: false,
-      },
-      changeNum: String,
-      changeStatus: String,
-      commitNum: String,
-      hasParent: {
-        type: Boolean,
-        observer: '_computeChainState',
-      },
-      latestPatchNum: String,
-      commitMessage: {
-        type: String,
-        value: '',
-      },
-      /** @type {?} */
-      revisionActions: {
-        type: Object,
-        notify: true,
-        value() { return {}; },
-      },
-      // If property binds directly to [[revisionActions.submit]] it is not
-      // updated when revisionActions doesn't contain submit action.
-      /** @type {?} */
-      _revisionSubmitAction: {
-        type: Object,
-        computed: '_getSubmitAction(revisionActions)',
-      },
-      // If property binds directly to [[revisionActions.rebase]] it is not
-      // updated when revisionActions doesn't contain rebase action.
-      /** @type {?} */
-      _revisionRebaseAction: {
-        type: Object,
-        computed: '_getRebaseAction(revisionActions)',
-      },
-      privateByDefault: String,
+        primaryActionKeys: {
+          type: Array,
+          value() {
+            return [
+              RevisionActions.SUBMIT,
+            ];
+          },
+        },
+        disableEdit: {
+          type: Boolean,
+          value: false,
+        },
+        _hasKnownChainState: {
+          type: Boolean,
+          value: false,
+        },
+        _hideQuickApproveAction: {
+          type: Boolean,
+          value: false,
+        },
+        changeNum: String,
+        changeStatus: String,
+        commitNum: String,
+        hasParent: {
+          type: Boolean,
+          observer: '_computeChainState',
+        },
+        latestPatchNum: String,
+        commitMessage: {
+          type: String,
+          value: '',
+        },
+        /** @type {?} */
+        revisionActions: {
+          type: Object,
+          notify: true,
+          value() { return {}; },
+        },
+        // If property binds directly to [[revisionActions.submit]] it is not
+        // updated when revisionActions doesn't contain submit action.
+        /** @type {?} */
+        _revisionSubmitAction: {
+          type: Object,
+          computed: '_getSubmitAction(revisionActions)',
+        },
+        // If property binds directly to [[revisionActions.rebase]] it is not
+        // updated when revisionActions doesn't contain rebase action.
+        /** @type {?} */
+        _revisionRebaseAction: {
+          type: Object,
+          computed: '_getRebaseAction(revisionActions)',
+        },
+        privateByDefault: String,
 
-      _loading: {
-        type: Boolean,
-        value: true,
-      },
-      _actionLoadingMessage: {
-        type: String,
-        value: '',
-      },
-      _allActionValues: {
-        type: Array,
-        computed: '_computeAllActions(actions.*, revisionActions.*,' +
+        _loading: {
+          type: Boolean,
+          value: true,
+        },
+        _actionLoadingMessage: {
+          type: String,
+          value: '',
+        },
+        _allActionValues: {
+          type: Array,
+          computed: '_computeAllActions(actions.*, revisionActions.*,' +
             'primaryActionKeys.*, _additionalActions.*, change, ' +
             '_actionPriorityOverrides.*)',
-      },
-      _topLevelActions: {
-        type: Array,
-        computed: '_computeTopLevelActions(_allActionValues.*, ' +
-            '_hiddenActions.*, _overflowActions.*)',
-        observer: '_filterPrimaryActions',
-      },
-      _topLevelPrimaryActions: Array,
-      _topLevelSecondaryActions: Array,
-      _menuActions: {
-        type: Array,
-        computed: '_computeMenuActions(_allActionValues.*, ' +
-            '_hiddenActions.*, _overflowActions.*)',
-      },
-      _overflowActions: {
-        type: Array,
-        value() {
-          const value = [
-            {
-              type: ActionType.CHANGE,
-              key: ChangeActions.WIP,
-            },
-            {
-              type: ActionType.CHANGE,
-              key: ChangeActions.DELETE,
-            },
-            {
-              type: ActionType.REVISION,
-              key: RevisionActions.CHERRYPICK,
-            },
-            {
-              type: ActionType.CHANGE,
-              key: ChangeActions.MOVE,
-            },
-            {
-              type: ActionType.REVISION,
-              key: RevisionActions.DOWNLOAD,
-            },
-            {
-              type: ActionType.CHANGE,
-              key: ChangeActions.IGNORE,
-            },
-            {
-              type: ActionType.CHANGE,
-              key: ChangeActions.UNIGNORE,
-            },
-            {
-              type: ActionType.CHANGE,
-              key: ChangeActions.REVIEWED,
-            },
-            {
-              type: ActionType.CHANGE,
-              key: ChangeActions.UNREVIEWED,
-            },
-            {
-              type: ActionType.CHANGE,
-              key: ChangeActions.PRIVATE,
-            },
-            {
-              type: ActionType.CHANGE,
-              key: ChangeActions.PRIVATE_DELETE,
-            },
-            {
-              type: ActionType.CHANGE,
-              key: ChangeActions.FOLLOW_UP,
-            },
-          ];
-          return value;
         },
-      },
-      _actionPriorityOverrides: {
-        type: Array,
-        value() { return []; },
-      },
-      _additionalActions: {
-        type: Array,
-        value() { return []; },
-      },
-      _hiddenActions: {
-        type: Array,
-        value() { return []; },
-      },
-      _disabledMenuActions: {
-        type: Array,
-        value() { return []; },
-      },
-      // editPatchsetLoaded == "does the current selected patch range have
-      // 'edit' as one of either basePatchNum or patchNum".
-      editPatchsetLoaded: {
-        type: Boolean,
-        value: false,
-      },
-      // editMode == "is edit mode enabled in the file list".
-      editMode: {
-        type: Boolean,
-        value: false,
-      },
-      editBasedOnCurrentPatchSet: {
-        type: Boolean,
-        value: true,
-      },
-    },
+        _topLevelActions: {
+          type: Array,
+          computed: '_computeTopLevelActions(_allActionValues.*, ' +
+            '_hiddenActions.*, _overflowActions.*)',
+          observer: '_filterPrimaryActions',
+        },
+        _topLevelPrimaryActions: Array,
+        _topLevelSecondaryActions: Array,
+        _menuActions: {
+          type: Array,
+          computed: '_computeMenuActions(_allActionValues.*, ' +
+            '_hiddenActions.*, _overflowActions.*)',
+        },
+        _overflowActions: {
+          type: Array,
+          value() {
+            const value = [
+              {
+                type: ActionType.CHANGE,
+                key: ChangeActions.WIP,
+              },
+              {
+                type: ActionType.CHANGE,
+                key: ChangeActions.DELETE,
+              },
+              {
+                type: ActionType.REVISION,
+                key: RevisionActions.CHERRYPICK,
+              },
+              {
+                type: ActionType.CHANGE,
+                key: ChangeActions.MOVE,
+              },
+              {
+                type: ActionType.REVISION,
+                key: RevisionActions.DOWNLOAD,
+              },
+              {
+                type: ActionType.CHANGE,
+                key: ChangeActions.IGNORE,
+              },
+              {
+                type: ActionType.CHANGE,
+                key: ChangeActions.UNIGNORE,
+              },
+              {
+                type: ActionType.CHANGE,
+                key: ChangeActions.REVIEWED,
+              },
+              {
+                type: ActionType.CHANGE,
+                key: ChangeActions.UNREVIEWED,
+              },
+              {
+                type: ActionType.CHANGE,
+                key: ChangeActions.PRIVATE,
+              },
+              {
+                type: ActionType.CHANGE,
+                key: ChangeActions.PRIVATE_DELETE,
+              },
+              {
+                type: ActionType.CHANGE,
+                key: ChangeActions.FOLLOW_UP,
+              },
+            ];
+            return value;
+          },
+        },
+        _actionPriorityOverrides: {
+          type: Array,
+          value() { return []; },
+        },
+        _additionalActions: {
+          type: Array,
+          value() { return []; },
+        },
+        _hiddenActions: {
+          type: Array,
+          value() { return []; },
+        },
+        _disabledMenuActions: {
+          type: Array,
+          value() { return []; },
+        },
+        // editPatchsetLoaded == "does the current selected patch range have
+        // 'edit' as one of either basePatchNum or patchNum".
+        editPatchsetLoaded: {
+          type: Boolean,
+          value: false,
+        },
+        // editMode == "is edit mode enabled in the file list".
+        editMode: {
+          type: Boolean,
+          value: false,
+        },
+        editBasedOnCurrentPatchSet: {
+          type: Boolean,
+          value: true,
+        },
+      };
+    }
 
-    ActionType,
-    ChangeActions,
-    RevisionActions,
-
-    behaviors: [
-      Gerrit.FireBehavior,
-      Gerrit.PatchSetBehavior,
-      Gerrit.RESTClientBehavior,
-    ],
-
-    observers: [
-      '_actionsChanged(actions.*, revisionActions.*, _additionalActions.*)',
-      '_changeChanged(change)',
-      '_editStatusChanged(editMode, editPatchsetLoaded, ' +
+    static get observers() {
+      return [
+        '_actionsChanged(actions.*, revisionActions.*, _additionalActions.*)',
+        '_changeChanged(change)',
+        '_editStatusChanged(editMode, editPatchsetLoaded, ' +
           'editBasedOnCurrentPatchSet, disableEdit, actions.*, change.*)',
-    ],
+      ];
+    }
 
-    listeners: {
-      'fullscreen-overlay-opened': '_handleHideBackgroundContent',
-      'fullscreen-overlay-closed': '_handleShowBackgroundContent',
-    },
+    created() {
+      super.created();
+      this.addEventListener('fullscreen-overlay-opened',
+          () => this._handleHideBackgroundContent());
+      this.addEventListener('fullscreen-overlay-closed',
+          () => this._handleShowBackgroundContent());
+    }
 
     ready() {
+      super.ready();
       this.$.jsAPI.addElement(this.$.jsAPI.Element.CHANGE_ACTIONS, this);
       this._handleLoadingComplete();
-    },
+    }
 
     _getSubmitAction(revisionActions) {
       return this._getRevisionAction(revisionActions, 'submit', null);
-    },
+    }
 
     _getRebaseAction(revisionActions) {
       return this._getRevisionAction(revisionActions, 'rebase',
           {rebaseOnCurrent: null}
       );
-    },
+    }
 
     _getRevisionAction(revisionActions, actionName, emptyActionValue) {
       if (!revisionActions) {
@@ -451,7 +466,7 @@
         return emptyActionValue;
       }
       return revisionActions[actionName];
-    },
+    }
 
     reload() {
       if (!this.changeNum || !this.latestPatchNum) {
@@ -469,11 +484,11 @@
         this._loading = false;
         throw err;
       });
-    },
+    }
 
     _handleLoadingComplete() {
       Gerrit.awaitPluginsLoaded().then(() => this._loading = false);
-    },
+    }
 
     _updateRebaseAction(revisionActions) {
       if (revisionActions && revisionActions.rebase) {
@@ -485,11 +500,11 @@
         this._parentIsCurrent = true;
       }
       return revisionActions;
-    },
+    }
 
     _changeChanged() {
       this.reload();
-    },
+    }
 
     addActionButton(type, label) {
       if (type !== ActionType.CHANGE && type !== ActionType.REVISION) {
@@ -504,7 +519,7 @@
       };
       this.push('_additionalActions', action);
       return action.__key;
-    },
+    }
 
     removeActionButton(key) {
       const idx = this._indexOfActionButtonWithKey(key);
@@ -512,7 +527,7 @@
         return;
       }
       this.splice('_additionalActions', idx, 1);
-    },
+    }
 
     setActionButtonProp(key, prop, value) {
       this.set([
@@ -520,7 +535,7 @@
         this._indexOfActionButtonWithKey(key),
         prop,
       ], value);
-    },
+    }
 
     setActionOverflow(type, key, overflow) {
       if (type !== ActionType.CHANGE && type !== ActionType.REVISION) {
@@ -537,7 +552,7 @@
       } else if (overflow) {
         this.push('_overflowActions', action);
       }
-    },
+    }
 
     setActionPriority(type, key, priority) {
       if (type !== ActionType.CHANGE && type !== ActionType.REVISION) {
@@ -556,7 +571,7 @@
       } else {
         this.push('_actionPriorityOverrides', action);
       }
-    },
+    }
 
     setActionHidden(type, key, hidden) {
       if (type !== ActionType.CHANGE && type !== ActionType.REVISION) {
@@ -569,7 +584,7 @@
       } else if (!hidden && idx !== -1) {
         this.splice('_hiddenActions', idx, 1);
       }
-    },
+    }
 
     getActionDetails(action) {
       if (this.revisionActions[action]) {
@@ -577,7 +592,7 @@
       } else if (this.actions[action]) {
         return this.actions[action];
       }
-    },
+    }
 
     _indexOfActionButtonWithKey(key) {
       for (let i = 0; i < this._additionalActions.length; i++) {
@@ -586,20 +601,20 @@
         }
       }
       return -1;
-    },
+    }
 
     _getRevisionActions() {
       return this.$.restAPI.getChangeRevisionActions(this.changeNum,
           this.latestPatchNum);
-    },
+    }
 
     _shouldHideActions(actions, loading) {
       return loading || !actions || !actions.base || !actions.base.length;
-    },
+    }
 
     _keyCount(changeRecord) {
       return Object.keys((changeRecord && changeRecord.base) || {}).length;
-    },
+    }
 
     _actionsChanged(actionsChangeRecord, revisionActionsChangeRecord,
         additionalActionsChangeRecord) {
@@ -626,7 +641,7 @@
           this.set('revisionActions.download', DOWNLOAD_ACTION);
         }
       }
-    },
+    }
 
     /**
        * @param {string=} actionName
@@ -638,7 +653,7 @@
         // see https://github.com/Polymer/polymer/issues/2631
         this.notifyPath('actions.' + actionName, false);
       }
-    },
+    }
 
     _editStatusChanged(editMode, editPatchsetLoaded,
         editBasedOnCurrentPatchSet, disableEdit) {
@@ -705,13 +720,13 @@
         // Remove edit button.
         this._deleteAndNotify('edit');
       }
-    },
+    }
 
     _getValuesFor(obj) {
       return Object.keys(obj).map(key => {
         return obj[key];
       });
-    },
+    }
 
     _getLabelStatus(label) {
       if (label.approved) {
@@ -723,7 +738,7 @@
       } else {
         return LabelStatus.NEED;
       }
-    },
+    }
 
     /**
      * Get highest score for last missing permitted label for current change.
@@ -771,7 +786,7 @@
         }
       }
       return null;
-    },
+    }
 
     hideQuickApproveAction() {
       this._topLevelSecondaryActions =
@@ -779,7 +794,7 @@
           return sa.key !== QUICK_APPROVE_ACTION.key;
         });
       this._hideQuickApproveAction = true;
-    },
+    }
 
     _getQuickApproveAction() {
       if (this._hideQuickApproveAction) {
@@ -798,7 +813,7 @@
       review.labels[approval.label] = approval.score;
       action.payload = review;
       return action;
-    },
+    }
 
     _getActionValues(actionsChangeRecord, primariesChangeRecord,
         additionalActionsChangeRecord, type) {
@@ -843,7 +858,7 @@
         return Object.assign({}, a);
       });
       return result.concat(additionalActions).concat(pluginActions);
-    },
+    }
 
     _populateActionUrl(action) {
       const patchNum =
@@ -851,7 +866,7 @@
       this.$.restAPI.getChangeActionURL(
           this.changeNum, patchNum, '/' + action.__key)
           .then(url => action.__url = url);
-    },
+    }
 
     /**
      * Given a change action, return a display label that uses the appropriate
@@ -867,7 +882,7 @@
       }
       // Otherwise, just map the name to sentence case.
       return this._toSentenceCase(action.label);
-    },
+    }
 
     /**
      * Capitalize the first letter and lowecase all others.
@@ -877,16 +892,16 @@
     _toSentenceCase(s) {
       if (!s.length) { return ''; }
       return s[0].toUpperCase() + s.slice(1).toLowerCase();
-    },
+    }
 
     _computeLoadingLabel(action) {
       return ActionLoadingLabels[action] || 'Working...';
-    },
+    }
 
     _canSubmitChange() {
       return this.$.jsAPI.canSubmitChange(this.change,
           this._getRevision(this.change, this.latestPatchNum));
-    },
+    }
 
     _getRevision(change, patchNum) {
       for (const rev of Object.values(change.revisions)) {
@@ -895,24 +910,24 @@
         }
       }
       return null;
-    },
+    }
 
     _modifyRevertMsg() {
       return this.$.jsAPI.modifyRevertMsg(this.change,
           this.$.confirmRevertDialog.message, this.commitMessage);
-    },
+    }
 
     showRevertDialog() {
       this.$.confirmRevertDialog.populateRevertMessage(
           this.commitMessage, this.change.current_revision);
       this.$.confirmRevertDialog.message = this._modifyRevertMsg();
       this._showActionDialog(this.$.confirmRevertDialog);
-    },
+    }
 
     _modifyRevertSubmissionMsg() {
       return this.$.jsAPI.modifyRevertSubmissionMsg(this.change,
           this.$.confirmRevertSubmissionDialog.message, this.commitMessage);
-    },
+    }
 
     showRevertSubmissionDialog() {
       this.$.confirmRevertSubmissionDialog.populateRevertSubmissionMessage(
@@ -920,7 +935,7 @@
       this.$.confirmRevertSubmissionDialog.message =
           this._modifyRevertSubmissionMsg();
       this._showActionDialog(this.$.confirmRevertSubmissionDialog);
-    },
+    }
 
     _handleActionTap(e) {
       e.preventDefault();
@@ -938,7 +953,7 @@
       }
       const type = el.getAttribute('data-action-type');
       this._handleAction(type, key);
-    },
+    }
 
     _handleOveflowItemTap(e) {
       e.preventDefault();
@@ -950,7 +965,7 @@
         return;
       }
       this._handleAction(e.detail.action.__type, e.detail.action.__key);
-    },
+    }
 
     _handleAction(type, key) {
       this.$.reporting.reportInteraction(`${type}-${key}`);
@@ -964,7 +979,7 @@
         default:
           this._fireAction(this._prependSlash(key), this.actions[key], false);
       }
-    },
+    }
 
     _handleChangeAction(key) {
       let action;
@@ -1015,7 +1030,7 @@
         default:
           this._fireAction(this._prependSlash(key), this.actions[key], false);
       }
-    },
+    }
 
     _handleRevisionAction(key) {
       switch (key) {
@@ -1037,11 +1052,11 @@
           this._fireAction(this._prependSlash(key),
               this.revisionActions[key], true);
       }
-    },
+    }
 
     _prependSlash(key) {
       return key === '/' ? key : `/${key}`;
-    },
+    }
 
     /**
      * _hasKnownChainState set to true true if hasParent is defined (can be
@@ -1049,25 +1064,25 @@
      */
     _computeChainState(hasParent) {
       this._hasKnownChainState = true;
-    },
+    }
 
     _calculateDisabled(action, hasKnownChainState) {
       if (action.__key === 'rebase' && hasKnownChainState === false) {
         return true;
       }
       return !action.enabled;
-    },
+    }
 
     _handleConfirmDialogCancel() {
       this._hideAllDialogs();
-    },
+    }
 
     _hideAllDialogs() {
       const dialogEls =
           Polymer.dom(this.root).querySelectorAll('.confirmDialog');
       for (const dialogEl of dialogEls) { dialogEl.hidden = true; }
       this.$.overlay.close();
-    },
+    }
 
     _handleRebaseConfirm(e) {
       const el = this.$.confirmRebase;
@@ -1075,15 +1090,15 @@
       this.$.overlay.close();
       el.hidden = true;
       this._fireAction('/rebase', this.revisionActions.rebase, true, payload);
-    },
+    }
 
     _handleCherrypickConfirm() {
       this._handleCherryPickRestApi(false);
-    },
+    }
 
     _handleCherrypickConflictConfirm() {
       this._handleCherryPickRestApi(true);
-    },
+    }
 
     _handleCherryPickRestApi(conflicts) {
       const el = this.$.confirmCherrypick;
@@ -1108,7 +1123,7 @@
             allow_conflicts: conflicts,
           }
       );
-    },
+    }
 
     _handleMoveConfirm() {
       const el = this.$.confirmMove;
@@ -1127,7 +1142,7 @@
             message: el.message,
           }
       );
-    },
+    }
 
     _handleRevertDialogConfirm() {
       const el = this.$.confirmRevertDialog;
@@ -1135,7 +1150,7 @@
       el.hidden = true;
       this._fireAction('/revert', this.actions.revert, false,
           {message: el.message});
-    },
+    }
 
     _handleRevertSubmissionDialogConfirm() {
       const el = this.$.confirmRevertSubmissionDialog;
@@ -1143,7 +1158,7 @@
       el.hidden = true;
       this._fireAction('/revert_submission', this.actions.revert_submission,
           false, {message: el.message});
-    },
+    }
 
     _handleAbandonDialogConfirm() {
       const el = this.$.confirmAbandonDialog;
@@ -1151,38 +1166,38 @@
       el.hidden = true;
       this._fireAction('/abandon', this.actions.abandon, false,
           {message: el.message});
-    },
+    }
 
     _handleCreateFollowUpChange() {
       this.$.createFollowUpChange.handleCreateChange();
       this._handleCloseCreateFollowUpChange();
-    },
+    }
 
     _handleCloseCreateFollowUpChange() {
       this.$.overlay.close();
-    },
+    }
 
     _handleDeleteConfirm() {
       this._fireAction('/', this.actions[ChangeActions.DELETE], false);
-    },
+    }
 
     _handleDeleteEditConfirm() {
       this._hideAllDialogs();
 
       this._fireAction('/edit', this.actions.deleteEdit, false);
-    },
+    }
 
     _handleSubmitConfirm() {
       if (!this._canSubmitChange()) { return; }
       this._hideAllDialogs();
       this._fireAction('/submit', this.revisionActions.submit, true);
-    },
+    }
 
     _getActionOverflowIndex(type, key) {
       return this._overflowActions.findIndex(action => {
         return action.type === type && action.key === key;
       });
-    },
+    }
 
     _setLoadingOnButtonWithKey(type, key) {
       this._actionLoadingMessage = this._computeLoadingLabel(key);
@@ -1205,7 +1220,7 @@
         buttonEl.removeAttribute('loading');
         buttonEl.disabled = false;
       }.bind(this);
-    },
+    }
 
     /**
      * @param {string} endpoint
@@ -1219,7 +1234,7 @@
 
       this._send(action.method, opt_payload, endpoint, revAction, cleanupFn,
           action).then(this._handleResponse.bind(this, action));
-    },
+    }
 
     _showActionDialog(dialog) {
       this._hideAllDialogs();
@@ -1230,7 +1245,7 @@
           dialog.resetFocus();
         }
       });
-    },
+    }
 
     // TODO(rmistry): Redo this after
     // https://bugs.chromium.org/p/gerrit/issues/detail?id=4671 is resolved.
@@ -1238,7 +1253,7 @@
       const labels = this.$.jsAPI.getLabelValuesPostRevert(this.change);
       if (!labels) { return Promise.resolve(); }
       return this.$.restAPI.saveChangeReview(newChangeId, 'current', {labels});
-    },
+    }
 
     _handleResponse(action, response) {
       if (!response) { return; }
@@ -1273,7 +1288,7 @@
             break;
         }
       });
-    },
+    }
 
     _handleResponseError(action, response, body) {
       if (action && action.__key === RevisionActions.CHERRYPICK) {
@@ -1290,7 +1305,7 @@
           throw Error(errText);
         }
       });
-    },
+    }
 
     /**
      * @param {string} method
@@ -1333,58 +1348,58 @@
                   return response;
                 });
           });
-    },
+    }
 
     _handleAbandonTap() {
       this._showActionDialog(this.$.confirmAbandonDialog);
-    },
+    }
 
     _handleCherrypickTap() {
       this.$.confirmCherrypick.branch = '';
       this._showActionDialog(this.$.confirmCherrypick);
-    },
+    }
 
     _handleMoveTap() {
       this.$.confirmMove.branch = '';
       this.$.confirmMove.message = '';
       this._showActionDialog(this.$.confirmMove);
-    },
+    }
 
     _handleDownloadTap() {
       this.fire('download-tap', null, {bubbles: false});
-    },
+    }
 
     _handleDeleteTap() {
       this._showActionDialog(this.$.confirmDeleteDialog);
-    },
+    }
 
     _handleDeleteEditTap() {
       this._showActionDialog(this.$.confirmDeleteEditDialog);
-    },
+    }
 
     _handleFollowUpTap() {
       this._showActionDialog(this.$.createFollowUpDialog);
-    },
+    }
 
     _handleWipTap() {
       this._fireAction('/wip', this.actions.wip, false);
-    },
+    }
 
     _handlePublishEditTap() {
       this._fireAction('/edit:publish', this.actions.publishEdit, false);
-    },
+    }
 
     _handleRebaseEditTap() {
       this._fireAction('/edit:rebase', this.actions.rebaseEdit, false);
-    },
+    }
 
     _handleHideBackgroundContent() {
       this.$.mainContent.classList.add('overlayOpen');
-    },
+    }
 
     _handleShowBackgroundContent() {
       this.$.mainContent.classList.remove('overlayOpen');
-    },
+    }
 
     /**
      * Merge sources of change actions into a single ordered array of action
@@ -1427,7 +1442,7 @@
             }
             return action;
           });
-    },
+    }
 
     _getActionPriority(action) {
       if (action.__type && action.__key) {
@@ -1449,7 +1464,7 @@
         return ActionPriority.REVISION;
       }
       return ActionPriority.DEFAULT;
-    },
+    }
 
     /**
      * Sort comparator to define the order of change actions.
@@ -1463,7 +1478,7 @@
       } else {
         return priorityDelta;
       }
-    },
+    }
 
     _computeTopLevelActions(actionRecord, hiddenActionsRecord) {
       const hiddenActions = hiddenActionsRecord.base || [];
@@ -1471,14 +1486,14 @@
         const overflow = this._getActionOverflowIndex(a.__type, a.__key) !== -1;
         return !(overflow || hiddenActions.includes(a.__key));
       });
-    },
+    }
 
     _filterPrimaryActions(_topLevelActions) {
       this._topLevelPrimaryActions = _topLevelActions.filter(action =>
         action.__primary);
       this._topLevelSecondaryActions = _topLevelActions.filter(action =>
         !action.__primary);
-    },
+    }
 
     _computeMenuActions(actionRecord, hiddenActionsRecord) {
       const hiddenActions = hiddenActionsRecord.base || [];
@@ -1495,7 +1510,7 @@
           tooltip: action.title,
         };
       });
-    },
+    }
 
     /**
      * Occasionally, a change created by a change action is not yet knwon to the
@@ -1529,22 +1544,24 @@
         };
         check();
       });
-    },
+    }
 
     _handleEditTap() {
       this.dispatchEvent(new CustomEvent('edit-tap', {bubbles: false}));
-    },
+    }
 
     _handleStopEditTap() {
       this.dispatchEvent(new CustomEvent('stop-edit-tap', {bubbles: false}));
-    },
+    }
 
     _computeHasTooltip(title) {
       return !!title;
-    },
+    }
 
     _computeHasIcon(action) {
       return action.icon ? '' : 'hidden';
-    },
-  });
+    }
+  }
+
+  customElements.define(GrChangeActions.is, GrChangeActions);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
index 310a1a6..e0d9676 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
@@ -48,105 +48,111 @@
     TRUSTED: 'TRUSTED',
   };
 
-  Polymer({
-    is: 'gr-change-metadata',
-
+  /**
+    * @appliesMixin Gerrit.RESTClientMixin
+    */
+  class GrChangeMetadata extends Polymer.mixinBehaviors( [
+    Gerrit.RESTClientBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-change-metadata'; }
     /**
      * Fired when the change topic is changed.
      *
      * @event topic-changed
      */
 
-    properties: {
+    static get properties() {
+      return {
       /** @type {?} */
-      change: Object,
-      labels: {
-        type: Object,
-        notify: true,
-      },
-      account: Object,
-      /** @type {?} */
-      revision: Object,
-      commitInfo: Object,
-      _mutable: {
-        type: Boolean,
-        computed: '_computeIsMutable(account)',
-      },
-      /** @type {?} */
-      serverConfig: Object,
-      parentIsCurrent: Boolean,
-      _notCurrentMessage: {
-        type: String,
-        value: NOT_CURRENT_MESSAGE,
-        readOnly: true,
-      },
-      _topicReadOnly: {
-        type: Boolean,
-        computed: '_computeTopicReadOnly(_mutable, change)',
-      },
-      _hashtagReadOnly: {
-        type: Boolean,
-        computed: '_computeHashtagReadOnly(_mutable, change)',
-      },
-      /**
+        change: Object,
+        labels: {
+          type: Object,
+          notify: true,
+        },
+        account: Object,
+        /** @type {?} */
+        revision: Object,
+        commitInfo: Object,
+        _mutable: {
+          type: Boolean,
+          computed: '_computeIsMutable(account)',
+        },
+        /** @type {?} */
+        serverConfig: Object,
+        parentIsCurrent: Boolean,
+        _notCurrentMessage: {
+          type: String,
+          value: NOT_CURRENT_MESSAGE,
+          readOnly: true,
+        },
+        _topicReadOnly: {
+          type: Boolean,
+          computed: '_computeTopicReadOnly(_mutable, change)',
+        },
+        _hashtagReadOnly: {
+          type: Boolean,
+          computed: '_computeHashtagReadOnly(_mutable, change)',
+        },
+        /**
        * @type {Gerrit.PushCertificateValidation}
        */
-      _pushCertificateValidation: {
-        type: Object,
-        computed: '_computePushCertificateValidation(serverConfig, change)',
-      },
-      _showRequirements: {
-        type: Boolean,
-        computed: '_computeShowRequirements(change)',
-      },
-
-      _assignee: Array,
-      _isWip: {
-        type: Boolean,
-        computed: '_computeIsWip(change)',
-      },
-      _newHashtag: String,
-
-      _settingTopic: {
-        type: Boolean,
-        value: false,
-      },
-
-      _currentParents: {
-        type: Array,
-        computed: '_computeParents(change)',
-      },
-
-      /** @type {?} */
-      _CHANGE_ROLE: {
-        type: Object,
-        readOnly: true,
-        value: {
-          OWNER: 'owner',
-          UPLOADER: 'uploader',
-          AUTHOR: 'author',
-          COMMITTER: 'committer',
+        _pushCertificateValidation: {
+          type: Object,
+          computed: '_computePushCertificateValidation(serverConfig, change)',
         },
-      },
-    },
+        _showRequirements: {
+          type: Boolean,
+          computed: '_computeShowRequirements(change)',
+        },
 
-    behaviors: [
-      Gerrit.RESTClientBehavior,
-    ],
+        _assignee: Array,
+        _isWip: {
+          type: Boolean,
+          computed: '_computeIsWip(change)',
+        },
+        _newHashtag: String,
 
-    observers: [
-      '_changeChanged(change)',
-      '_labelsChanged(change.labels)',
-      '_assigneeChanged(_assignee.*)',
-    ],
+        _settingTopic: {
+          type: Boolean,
+          value: false,
+        },
+
+        _currentParents: {
+          type: Array,
+          computed: '_computeParents(change)',
+        },
+
+        /** @type {?} */
+        _CHANGE_ROLE: {
+          type: Object,
+          readOnly: true,
+          value: {
+            OWNER: 'owner',
+            UPLOADER: 'uploader',
+            AUTHOR: 'author',
+            COMMITTER: 'committer',
+          },
+        },
+      };
+    }
+
+    static get observers() {
+      return [
+        '_changeChanged(change)',
+        '_labelsChanged(change.labels)',
+        '_assigneeChanged(_assignee.*)',
+      ];
+    }
 
     _labelsChanged(labels) {
       this.labels = Object.assign({}, labels) || null;
-    },
+    }
 
     _changeChanged(change) {
       this._assignee = change.assignee ? [change.assignee] : [];
-    },
+    }
 
     _assigneeChanged(assigneeRecord) {
       if (!this.change) { return; }
@@ -162,11 +168,11 @@
         this.set(['change', 'assignee'], undefined);
         this.$.restAPI.deleteAssignee(this.change._number);
       }
-    },
+    }
 
     _computeHideStrategy(change) {
       return !this.changeIsOpen(change);
-    },
+    }
 
     /**
      * @param {Object} commitInfo
@@ -184,15 +190,15 @@
             config: serverConfig,
           });
       return weblinks.length ? weblinks : null;
-    },
+    }
 
     _computeStrategy(change) {
       return SubmitTypeLabel[change.submit_type];
-    },
+    }
 
     _computeLabelNames(labels) {
       return Object.keys(labels).sort();
-    },
+    }
 
     _handleTopicChanged(e, topic) {
       const lastTopic = this.change.topic;
@@ -207,19 +213,19 @@
                   'topic-changed', {bubbles: true, composed: true}));
             }
           });
-    },
+    }
 
     _showAddTopic(changeRecord, settingTopic) {
       const hasTopic = !!changeRecord &&
           !!changeRecord.base && !!changeRecord.base.topic;
       return !hasTopic && !settingTopic;
-    },
+    }
 
     _showTopicChip(changeRecord, settingTopic) {
       const hasTopic = !!changeRecord &&
           !!changeRecord.base && !!changeRecord.base.topic;
       return hasTopic && !settingTopic;
-    },
+    }
 
     _handleHashtagChanged(e) {
       const lastHashtag = this.change.hashtag;
@@ -234,7 +240,7 @@
               'hashtag-changed', {bubbles: true, composed: true}));
         }
       });
-    },
+    }
 
     _computeTopicReadOnly(mutable, change) {
       return !mutable ||
@@ -242,7 +248,7 @@
           !change.actions ||
           !change.actions.topic ||
           !change.actions.topic.enabled;
-    },
+    }
 
     _computeHashtagReadOnly(mutable, change) {
       return !mutable ||
@@ -250,7 +256,7 @@
           !change.actions ||
           !change.actions.hashtags ||
           !change.actions.hashtags.enabled;
-    },
+    }
 
     _computeAssigneeReadOnly(mutable, change) {
       return !mutable ||
@@ -258,17 +264,17 @@
           !change.actions ||
           !change.actions.assignee ||
           !change.actions.assignee.enabled;
-    },
+    }
 
     _computeTopicPlaceholder(_topicReadOnly) {
       // Action items in Material Design are uppercase -- placeholder label text
       // is sentence case.
       return _topicReadOnly ? 'No topic' : 'ADD TOPIC';
-    },
+    }
 
     _computeHashtagPlaceholder(_hashtagReadOnly) {
       return _hashtagReadOnly ? '' : HASHTAG_ADD_MESSAGE;
-    },
+    }
 
     _computeShowRequirements(change) {
       if (change.status !== this.ChangeStatus.NEW) {
@@ -281,7 +287,7 @@
       const hasLabels = !!change.labels &&
           Object.keys(change.labels).length > 0;
       return hasRequirements || hasLabels || !!change.work_in_progress;
-    },
+    }
 
     /**
      * @return {?Gerrit.PushCertificateValidation} object representing data for
@@ -326,7 +332,7 @@
         default:
           throw new Error(`unknown certificate status: ${key.status}`);
       }
-    },
+    }
 
     _problems(msg, key) {
       if (!key || !key.problems || key.problems.length === 0) {
@@ -334,26 +340,26 @@
       }
 
       return [msg + ':'].concat(key.problems).join('\n');
-    },
+    }
 
     _computeProjectURL(project) {
       return Gerrit.Nav.getUrlForProjectChanges(project);
-    },
+    }
 
     _computeBranchURL(project, branch) {
       if (!this.change || !this.change.status) return '';
       return Gerrit.Nav.getUrlForBranch(branch, project,
           this.change.status == this.ChangeStatus.NEW ? 'open' :
             this.change.status.toLowerCase());
-    },
+    }
 
     _computeTopicURL(topic) {
       return Gerrit.Nav.getUrlForTopic(topic);
-    },
+    }
 
     _computeHashtagURL(hashtag) {
       return Gerrit.Nav.getUrlForHashtag(hashtag);
-    },
+    }
 
     _handleTopicRemoved(e) {
       const target = Polymer.dom(e).rootTarget;
@@ -367,7 +373,7 @@
         target.disabled = false;
         return;
       });
-    },
+    }
 
     _handleHashtagRemoved(e) {
       e.preventDefault();
@@ -382,15 +388,15 @@
             target.disabled = false;
             return;
           });
-    },
+    }
 
     _computeIsWip(change) {
       return !!change.work_in_progress;
-    },
+    }
 
     _computeShowRoleClass(change, role) {
       return this._getNonOwnerRole(change, role) ? '' : 'hideDisplay';
-    },
+    }
 
     /**
      * Get the user with the specified role on the change. Returns null if the
@@ -427,7 +433,7 @@
       }
 
       return null;
-    },
+    }
 
     _computeParents(change) {
       if (!change || !change.current_revision ||
@@ -436,11 +442,11 @@
         return undefined;
       }
       return change.revisions[change.current_revision].commit.parents;
-    },
+    }
 
     _computeParentsLabel(parents) {
       return parents && parents.length > 1 ? 'Parents' : 'Parent';
-    },
+    }
 
     _computeParentListClass(parents, parentIsCurrent) {
       // Undefined check for polymer 2
@@ -453,24 +459,26 @@
         parents && parents.length > 1 ? 'merge' : 'nonMerge',
         parentIsCurrent ? 'current' : 'notCurrent',
       ].join(' ');
-    },
+    }
 
     _computeIsMutable(account) {
       return !!Object.keys(account).length;
-    },
+    }
 
     editTopic() {
       if (this._topicReadOnly || this.change.topic) { return; }
       // Cannot use `this.$.ID` syntax because the element exists inside of a
       // dom-if.
       this.$$('.topicEditableLabel').open();
-    },
+    }
 
     _getReviewerSuggestionsProvider(change) {
       const provider = GrReviewerSuggestionsProvider.create(this.$.restAPI,
           change._number, Gerrit.SUGGESTIONS_PROVIDERS_USERS_TYPES.ANY);
       provider.init();
       return provider;
-    },
-  });
+    }
+  }
+
+  customElements.define(GrChangeMetadata.is, GrChangeMetadata);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.js b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.js
index dfdcd59..2e0332b 100644
--- a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.js
+++ b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.js
@@ -17,47 +17,54 @@
 (function() {
   'use strict';
 
-  Polymer({
-    is: 'gr-change-requirements',
+  /**
+    * @appliesMixin Gerrit.RESTClientMixin
+    */
+  class GrChangeRequirements extends Polymer.mixinBehaviors( [
+    Gerrit.RESTClientBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-change-requirements'; }
 
-    properties: {
+    static get properties() {
+      return {
       /** @type {?} */
-      change: Object,
-      account: Object,
-      mutable: Boolean,
-      _requirements: {
-        type: Array,
-        computed: '_computeRequirements(change)',
-      },
-      _requiredLabels: {
-        type: Array,
-        value: () => [],
-      },
-      _optionalLabels: {
-        type: Array,
-        value: () => [],
-      },
-      _showWip: {
-        type: Boolean,
-        computed: '_computeShowWip(change)',
-      },
-      _showOptionalLabels: {
-        type: Boolean,
-        value: true,
-      },
-    },
+        change: Object,
+        account: Object,
+        mutable: Boolean,
+        _requirements: {
+          type: Array,
+          computed: '_computeRequirements(change)',
+        },
+        _requiredLabels: {
+          type: Array,
+          value: () => [],
+        },
+        _optionalLabels: {
+          type: Array,
+          value: () => [],
+        },
+        _showWip: {
+          type: Boolean,
+          computed: '_computeShowWip(change)',
+        },
+        _showOptionalLabels: {
+          type: Boolean,
+          value: true,
+        },
+      };
+    }
 
-    behaviors: [
-      Gerrit.RESTClientBehavior,
-    ],
-
-    observers: [
-      '_computeLabels(change.labels.*)',
-    ],
+    static get observers() {
+      return [
+        '_computeLabels(change.labels.*)',
+      ];
+    }
 
     _computeShowWip(change) {
       return change.work_in_progress;
-    },
+    }
 
     _computeRequirements(change) {
       const _requirements = [];
@@ -78,15 +85,15 @@
       }
 
       return _requirements;
-    },
+    }
 
     _computeRequirementClass(requirementStatus) {
       return requirementStatus ? 'approved' : '';
-    },
+    }
 
     _computeRequirementIcon(requirementStatus) {
       return requirementStatus ? 'gr-icons:check' : 'gr-icons:hourglass';
-    },
+    }
 
     _computeLabels(labelsRecord) {
       const labels = labelsRecord.base;
@@ -103,7 +110,7 @@
 
         this.push(path, {label, icon, style, labelInfo});
       }
-    },
+    }
 
     /**
      * @param {Object} labelInfo
@@ -114,7 +121,7 @@
       if (labelInfo.approved) { return 'gr-icons:check'; }
       if (labelInfo.rejected) { return 'gr-icons:close'; }
       return 'gr-icons:hourglass';
-    },
+    }
 
     /**
      * @param {Object} labelInfo
@@ -123,28 +130,30 @@
       if (labelInfo.approved) { return 'approved'; }
       if (labelInfo.rejected) { return 'rejected'; }
       return '';
-    },
+    }
 
     _computeShowOptional(optionalFieldsRecord) {
       return optionalFieldsRecord.base.length ? '' : 'hidden';
-    },
+    }
 
     _computeLabelValue(value) {
       return (value > 0 ? '+' : '') + value;
-    },
+    }
 
     _computeShowHideIcon(showOptionalLabels) {
       return showOptionalLabels ?
         'gr-icons:expand-less' :
         'gr-icons:expand-more';
-    },
+    }
 
     _computeSectionClass(show) {
       return show ? '' : 'hidden';
-    },
+    }
 
     _handleShowHide(e) {
       this._showOptionalLabels = !this._showOptionalLabels;
-    },
-  });
+    }
+  }
+
+  customElements.define(GrChangeRequirements.is, GrChangeRequirements);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
index ff63a32..5de378b 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
@@ -63,9 +63,21 @@
   const CHANGE_RELOAD_TIMING_LABEL = 'ChangeReloaded';
   const SEND_REPLY_TIMING_LABEL = 'SendReply';
 
-  Polymer({
-    is: 'gr-change-view',
-
+  /**
+    * @appliesMixin Gerrit.FireMixin
+    * @appliesMixin Gerrit.KeyboardShortcutMixin
+    * @appliesMixin Gerrit.PatchSetMixin
+    * @appliesMixin Gerrit.RESTClientMixin
+    */
+  class GrChangeView extends Polymer.mixinBehaviors( [
+    Gerrit.FireBehavior,
+    Gerrit.KeyboardShortcutBehavior,
+    Gerrit.PatchSetBehavior,
+    Gerrit.RESTClientBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-change-view'; }
     /**
      * Fired when the title of the page should change.
      *
@@ -84,230 +96,215 @@
      * @event show-auth-required
      */
 
-    properties: {
+    static get properties() {
+      return {
       /**
        * URL params passed from the router.
        */
-      params: {
-        type: Object,
-        observer: '_paramsChanged',
-      },
-      /** @type {?} */
-      viewState: {
-        type: Object,
-        notify: true,
-        value() { return {}; },
-        observer: '_viewStateChanged',
-      },
-      backPage: String,
-      hasParent: Boolean,
-      keyEventTarget: {
-        type: Object,
-        value() { return document.body; },
-      },
-      disableEdit: {
-        type: Boolean,
-        value: false,
-      },
-      disableDiffPrefs: {
-        type: Boolean,
-        value: false,
-      },
-      _diffPrefsDisabled: {
-        type: Boolean,
-        computed: '_computeDiffPrefsDisabled(disableDiffPrefs, _loggedIn)',
-      },
-      _commentThreads: Array,
-      /** @type {?} */
-      _serverConfig: {
-        type: Object,
-        observer: '_startUpdateCheckTimer',
-      },
-      _diffPrefs: Object,
-      _numFilesShown: {
-        type: Number,
-        value: DEFAULT_NUM_FILES_SHOWN,
-        observer: '_numFilesShownChanged',
-      },
-      _account: {
-        type: Object,
-        value: {},
-      },
-      _prefs: Object,
-      /** @type {?} */
-      _changeComments: Object,
-      _canStartReview: {
-        type: Boolean,
-        computed: '_computeCanStartReview(_change)',
-      },
-      _comments: Object,
-      /** @type {?} */
-      _change: {
-        type: Object,
-        observer: '_changeChanged',
-      },
-      _revisionInfo: {
-        type: Object,
-        computed: '_getRevisionInfo(_change)',
-      },
-      /** @type {?} */
-      _commitInfo: Object,
-      _currentRevision: {
-        type: Object,
-        computed: '_computeCurrentRevision(_change.current_revision, ' +
+        params: {
+          type: Object,
+          observer: '_paramsChanged',
+        },
+        /** @type {?} */
+        viewState: {
+          type: Object,
+          notify: true,
+          value() { return {}; },
+          observer: '_viewStateChanged',
+        },
+        backPage: String,
+        hasParent: Boolean,
+        keyEventTarget: {
+          type: Object,
+          value() { return document.body; },
+        },
+        disableEdit: {
+          type: Boolean,
+          value: false,
+        },
+        disableDiffPrefs: {
+          type: Boolean,
+          value: false,
+        },
+        _diffPrefsDisabled: {
+          type: Boolean,
+          computed: '_computeDiffPrefsDisabled(disableDiffPrefs, _loggedIn)',
+        },
+        _commentThreads: Array,
+        /** @type {?} */
+        _serverConfig: {
+          type: Object,
+          observer: '_startUpdateCheckTimer',
+        },
+        _diffPrefs: Object,
+        _numFilesShown: {
+          type: Number,
+          value: DEFAULT_NUM_FILES_SHOWN,
+          observer: '_numFilesShownChanged',
+        },
+        _account: {
+          type: Object,
+          value: {},
+        },
+        _prefs: Object,
+        /** @type {?} */
+        _changeComments: Object,
+        _canStartReview: {
+          type: Boolean,
+          computed: '_computeCanStartReview(_change)',
+        },
+        _comments: Object,
+        /** @type {?} */
+        _change: {
+          type: Object,
+          observer: '_changeChanged',
+        },
+        _revisionInfo: {
+          type: Object,
+          computed: '_getRevisionInfo(_change)',
+        },
+        /** @type {?} */
+        _commitInfo: Object,
+        _currentRevision: {
+          type: Object,
+          computed: '_computeCurrentRevision(_change.current_revision, ' +
             '_change.revisions)',
-      },
-      _files: Object,
-      _changeNum: String,
-      _diffDrafts: {
-        type: Object,
-        value() { return {}; },
-      },
-      _editingCommitMessage: {
-        type: Boolean,
-        value: false,
-      },
-      _hideEditCommitMessage: {
-        type: Boolean,
-        computed: '_computeHideEditCommitMessage(_loggedIn, ' +
+        },
+        _files: Object,
+        _changeNum: String,
+        _diffDrafts: {
+          type: Object,
+          value() { return {}; },
+        },
+        _editingCommitMessage: {
+          type: Boolean,
+          value: false,
+        },
+        _hideEditCommitMessage: {
+          type: Boolean,
+          computed: '_computeHideEditCommitMessage(_loggedIn, ' +
             '_editingCommitMessage, _change, _editMode)',
-      },
-      _diffAgainst: String,
-      /** @type {?string} */
-      _latestCommitMessage: {
-        type: String,
-        value: '',
-      },
-      _lineHeight: Number,
-      _changeIdCommitMessageError: {
-        type: String,
-        computed:
+        },
+        _diffAgainst: String,
+        /** @type {?string} */
+        _latestCommitMessage: {
+          type: String,
+          value: '',
+        },
+        _lineHeight: Number,
+        _changeIdCommitMessageError: {
+          type: String,
+          computed:
           '_computeChangeIdCommitMessageError(_latestCommitMessage, _change)',
-      },
-      /** @type {?} */
-      _patchRange: {
-        type: Object,
-      },
-      _filesExpanded: String,
-      _basePatchNum: String,
-      _selectedRevision: Object,
-      _currentRevisionActions: Object,
-      _allPatchSets: {
-        type: Array,
-        computed: 'computeAllPatchSets(_change, _change.revisions.*)',
-      },
-      _loggedIn: {
-        type: Boolean,
-        value: false,
-      },
-      _loading: Boolean,
-      /** @type {?} */
-      _projectConfig: Object,
-      _rebaseOnCurrent: Boolean,
-      _replyButtonLabel: {
-        type: String,
-        value: 'Reply',
-        computed: '_computeReplyButtonLabel(_diffDrafts.*, _canStartReview)',
-      },
-      _selectedPatchSet: String,
-      _shownFileCount: Number,
-      _initialLoadComplete: {
-        type: Boolean,
-        value: false,
-      },
-      _replyDisabled: {
-        type: Boolean,
-        value: true,
-        computed: '_computeReplyDisabled(_serverConfig)',
-      },
-      _changeStatus: {
-        type: String,
-        computed: 'changeStatusString(_change)',
-      },
-      _changeStatuses: {
-        type: String,
-        computed:
+        },
+        /** @type {?} */
+        _patchRange: {
+          type: Object,
+        },
+        _filesExpanded: String,
+        _basePatchNum: String,
+        _selectedRevision: Object,
+        _currentRevisionActions: Object,
+        _allPatchSets: {
+          type: Array,
+          computed: 'computeAllPatchSets(_change, _change.revisions.*)',
+        },
+        _loggedIn: {
+          type: Boolean,
+          value: false,
+        },
+        _loading: Boolean,
+        /** @type {?} */
+        _projectConfig: Object,
+        _rebaseOnCurrent: Boolean,
+        _replyButtonLabel: {
+          type: String,
+          value: 'Reply',
+          computed: '_computeReplyButtonLabel(_diffDrafts.*, _canStartReview)',
+        },
+        _selectedPatchSet: String,
+        _shownFileCount: Number,
+        _initialLoadComplete: {
+          type: Boolean,
+          value: false,
+        },
+        _replyDisabled: {
+          type: Boolean,
+          value: true,
+          computed: '_computeReplyDisabled(_serverConfig)',
+        },
+        _changeStatus: {
+          type: String,
+          computed: 'changeStatusString(_change)',
+        },
+        _changeStatuses: {
+          type: String,
+          computed:
           '_computeChangeStatusChips(_change, _mergeable, _submitEnabled)',
-      },
-      _commitCollapsed: {
-        type: Boolean,
-        value: true,
-      },
-      _relatedChangesCollapsed: {
-        type: Boolean,
-        value: true,
-      },
-      /** @type {?number} */
-      _updateCheckTimerHandle: Number,
-      _editMode: {
-        type: Boolean,
-        computed: '_computeEditMode(_patchRange.*, params.*)',
-      },
-      _showRelatedToggle: {
-        type: Boolean,
-        value: false,
-        observer: '_updateToggleContainerClass',
-      },
-      _parentIsCurrent: Boolean,
-      _submitEnabled: {
-        type: Boolean,
-        computed: '_isSubmitEnabled(_currentRevisionActions)',
-      },
+        },
+        _commitCollapsed: {
+          type: Boolean,
+          value: true,
+        },
+        _relatedChangesCollapsed: {
+          type: Boolean,
+          value: true,
+        },
+        /** @type {?number} */
+        _updateCheckTimerHandle: Number,
+        _editMode: {
+          type: Boolean,
+          computed: '_computeEditMode(_patchRange.*, params.*)',
+        },
+        _showRelatedToggle: {
+          type: Boolean,
+          value: false,
+          observer: '_updateToggleContainerClass',
+        },
+        _parentIsCurrent: Boolean,
+        _submitEnabled: {
+          type: Boolean,
+          computed: '_isSubmitEnabled(_currentRevisionActions)',
+        },
 
-      /** @type {?} */
-      _mergeable: {
-        type: Boolean,
-        value: undefined,
-      },
-      _showMessagesView: {
-        type: Boolean,
-        value: true,
-      },
-      _showFileTabContent: {
-        type: Boolean,
-        value: true,
-      },
-      /** @type {Array<string>} */
-      _dynamicTabHeaderEndpoints: {
-        type: Array,
-      },
-      _showPrimaryTabs: {
-        type: Boolean,
-        computed: '_computeShowPrimaryTabs(_dynamicTabHeaderEndpoints)',
-      },
-      /** @type {Array<string>} */
-      _dynamicTabContentEndpoints: {
-        type: Array,
-      },
-      _selectedFilesTabPluginEndpoint: {
-        type: String,
-      },
-    },
+        /** @type {?} */
+        _mergeable: {
+          type: Boolean,
+          value: undefined,
+        },
+        _showMessagesView: {
+          type: Boolean,
+          value: true,
+        },
+        _showFileTabContent: {
+          type: Boolean,
+          value: true,
+        },
+        /** @type {Array<string>} */
+        _dynamicTabHeaderEndpoints: {
+          type: Array,
+        },
+        _showPrimaryTabs: {
+          type: Boolean,
+          computed: '_computeShowPrimaryTabs(_dynamicTabHeaderEndpoints)',
+        },
+        /** @type {Array<string>} */
+        _dynamicTabContentEndpoints: {
+          type: Array,
+        },
+        _selectedFilesTabPluginEndpoint: {
+          type: String,
+        },
+      };
+    }
 
-    behaviors: [
-      Gerrit.FireBehavior,
-      Gerrit.KeyboardShortcutBehavior,
-      Gerrit.PatchSetBehavior,
-      Gerrit.RESTClientBehavior,
-    ],
-
-    listeners: {
-      'topic-changed': '_handleTopicChanged',
-      // When an overlay is opened in a mobile viewport, the overlay has a full
-      // screen view. When it has a full screen view, we do not want the
-      // background to be scrollable. This will eliminate background scroll by
-      // hiding most of the contents on the screen upon opening, and showing
-      // again upon closing.
-      'fullscreen-overlay-opened': '_handleHideBackgroundContent',
-      'fullscreen-overlay-closed': '_handleShowBackgroundContent',
-      'diff-comments-modified': '_handleReloadCommentThreads',
-    },
-
-    observers: [
-      '_labelsChanged(_change.labels.*)',
-      '_paramsAndChangeChanged(params, _change)',
-      '_patchNumChanged(_patchRange.patchNum)',
-    ],
+    static get observers() {
+      return [
+        '_labelsChanged(_change.labels.*)',
+        '_paramsAndChangeChanged(params, _change)',
+        '_patchNumChanged(_patchRange.patchNum)',
+      ];
+    }
 
     keyboardShortcuts() {
       return {
@@ -325,9 +322,32 @@
         [this.Shortcut.OPEN_DIFF_PREFS]: '_handleOpenDiffPrefsShortcut',
         [this.Shortcut.EDIT_TOPIC]: '_handleEditTopic',
       };
-    },
+    }
+
+    created() {
+      super.created();
+
+      this.addEventListener('topic-changed',
+          () => this._handleTopicChanged());
+
+      this.addEventListener(
+          // When an overlay is opened in a mobile viewport, the overlay has a full
+          // screen view. When it has a full screen view, we do not want the
+          // background to be scrollable. This will eliminate background scroll by
+          // hiding most of the contents on the screen upon opening, and showing
+          // again upon closing.
+          'fullscreen-overlay-opened',
+          () => this._handleHideBackgroundContent());
+
+      this.addEventListener('fullscreen-overlay-closed',
+          () => this._handleShowBackgroundContent());
+
+      this.addEventListener('diff-comments-modified',
+          () => this._handleReloadCommentThreads());
+    }
 
     attached() {
+      super.attached();
       this._getServerConfig().then(config => {
         this._serverConfig = config;
       });
@@ -363,24 +383,25 @@
           this._handleCommitMessageCancel.bind(this));
       this.listen(window, 'scroll', '_handleScroll');
       this.listen(document, 'visibilitychange', '_handleVisibilityChange');
-    },
+    }
 
     detached() {
+      super.detached();
       this.unlisten(window, 'scroll', '_handleScroll');
       this.unlisten(document, 'visibilitychange', '_handleVisibilityChange');
 
       if (this._updateCheckTimerHandle) {
         this._cancelUpdateCheckTimer();
       }
-    },
+    }
 
     get messagesList() {
       return this.$$('gr-messages-list');
-    },
+    }
 
     get threadList() {
       return this.$$('gr-thread-list');
-    },
+    }
 
     /**
      * @param {boolean=} opt_reset
@@ -397,7 +418,7 @@
           this.set('viewState.diffMode', 'SIDE_BY_SIDE');
         }
       });
-    },
+    }
 
     _handleToggleDiffMode(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
@@ -409,11 +430,11 @@
       } else {
         this.$.fileListHeader.setDiffViewMode(DiffViewMode.SIDE_BY_SIDE);
       }
-    },
+    }
 
     _handleCommentTabChange() {
       this._showMessagesView = this.$.commentTabs.selected === 0;
-    },
+    }
 
     _handleFileTabChange(e) {
       const selectedIndex = this.$$('#primaryTabs').selected;
@@ -429,7 +450,7 @@
         this.$.reporting.reportInteraction('tab-changed',
             `tabname: ${tabName}, source: ${source}`);
       }
-    },
+    }
 
     _handleShowTab(e) {
       const idx = this._dynamicTabContentEndpoints.indexOf(e.detail.tab);
@@ -440,12 +461,12 @@
       this.$$('#primaryTabs').selected = idx + 1;
       this.$$('#primaryTabs').scrollIntoView();
       this.$.reporting.reportInteraction('show-tab', e.detail.tab);
-    },
+    }
 
     _handleEditCommitMessage(e) {
       this._editingCommitMessage = true;
       this.$.commitMessageEditor.focusTextarea();
-    },
+    }
 
     _handleCommitMessageSave(e) {
       // Trim trailing whitespace from each line.
@@ -466,15 +487,15 @@
       }).catch(err => {
         this.$.commitMessageEditor.disabled = false;
       });
-    },
+    }
 
     _reloadWindow() {
       window.location.reload();
-    },
+    }
 
     _handleCommitMessageCancel(e) {
       this._editingCommitMessage = false;
-    },
+    }
 
     _computeChangeStatusChips(change, mergeable, submitEnabled) {
       // Polymer 2: check for undefined
@@ -498,7 +519,7 @@
         submitEnabled: !!submitEnabled,
       };
       return this.changeStatuses(change, options);
-    },
+    }
 
     _computeHideEditCommitMessage(loggedIn, editing, change, editMode) {
       if (!loggedIn || editing ||
@@ -508,7 +529,7 @@
       }
 
       return false;
-    },
+    }
 
     _handleReloadCommentThreads() {
       // Get any new drafts that have been saved in the diff view and show
@@ -518,7 +539,7 @@
             .map(c => Object.assign({}, c));
         Polymer.dom.flush();
       });
-    },
+    }
 
     _handleReloadDiffComments(e) {
       // Keeps the file list counts updated.
@@ -529,7 +550,7 @@
             e.detail.path);
         Polymer.dom.flush();
       });
-    },
+    }
 
     _computeTotalCommentCounts(unresolvedCount, changeComments) {
       if (!changeComments) return undefined;
@@ -543,7 +564,7 @@
           // Add a comma and space if both unresolved and draft comments exist.
           (unresolvedString && draftString ? ', ' : '') +
           draftString;
-    },
+    }
 
     _handleCommentSave(e) {
       const draft = e.detail.comment;
@@ -575,7 +596,7 @@
         return (c1.line || -1) - (c2.line || -1);
       });
       this._diffDrafts = diffDrafts;
-    },
+    }
 
     _handleCommentDiscard(e) {
       const draft = e.detail.comment;
@@ -609,16 +630,16 @@
         delete diffDrafts[draft.path];
       }
       this._diffDrafts = diffDrafts;
-    },
+    }
 
     _handleReplyTap(e) {
       e.preventDefault();
       this._openReplyDialog(this.$.replyDialog.FocusTarget.ANY);
-    },
+    }
 
     _handleOpenDiffPrefs() {
       this.$.fileList.openDiffPrefs();
-    },
+    }
 
     _handleOpenIncludedInDialog() {
       this.$.includedInDialog.loadData().then(() => {
@@ -626,11 +647,11 @@
         this.$.includedInOverlay.refit();
       });
       this.$.includedInOverlay.open();
-    },
+    }
 
     _handleIncludedInDialogClose(e) {
       this.$.includedInOverlay.close();
-    },
+    }
 
     _handleOpenDownloadDialog() {
       this.$.downloadOverlay.open().then(() => {
@@ -638,19 +659,19 @@
             .setFocusStops(this.$.downloadDialog.getFocusStops());
         this.$.downloadDialog.focus();
       });
-    },
+    }
 
     _handleDownloadDialogClose(e) {
       this.$.downloadOverlay.close();
-    },
+    }
 
     _handleOpenUploadHelpDialog(e) {
       this.$.uploadHelpOverlay.open();
-    },
+    }
 
     _handleCloseUploadHelpDialog(e) {
       this.$.uploadHelpOverlay.close();
-    },
+    }
 
     _handleMessageReply(e) {
       const msg = e.detail.message.message;
@@ -658,33 +679,33 @@
           line => { return '> ' + line; }).join('\n') + '\n\n';
       this.$.replyDialog.quote = quoteStr;
       this._openReplyDialog(this.$.replyDialog.FocusTarget.BODY);
-    },
+    }
 
     _handleHideBackgroundContent() {
       this.$.mainContent.classList.add('overlayOpen');
-    },
+    }
 
     _handleShowBackgroundContent() {
       this.$.mainContent.classList.remove('overlayOpen');
-    },
+    }
 
     _handleReplySent(e) {
       this.$.replyOverlay.close();
       this._reload().then(() => {
         this.$.reporting.timeEnd(SEND_REPLY_TIMING_LABEL);
       });
-    },
+    }
 
     _handleReplyCancel(e) {
       this.$.replyOverlay.close();
-    },
+    }
 
     _handleReplyAutogrow(e) {
       // If the textarea resizes, we need to re-fit the overlay.
       this.debounce('reply-overlay-refit', () => {
         this.$.replyOverlay.refit();
       }, REPLY_REFIT_DEBOUNCE_INTERVAL_MS);
-    },
+    }
 
     _handleShowReplyDialog(e) {
       let target = this.$.replyDialog.FocusTarget.REVIEWERS;
@@ -692,25 +713,25 @@
         target = this.$.replyDialog.FocusTarget.CCS;
       }
       this._openReplyDialog(target);
-    },
+    }
 
     _handleScroll() {
       this.debounce('scroll', () => {
         this.viewState.scrollTop = document.body.scrollTop;
       }, 150);
-    },
+    }
 
     _setShownFiles(e) {
       this._shownFileCount = e.detail.length;
-    },
+    }
 
     _expandAllDiffs() {
       this.$.fileList.expandAllDiffs();
-    },
+    }
 
     _collapseAllDiffs() {
       this.$.fileList.collapseAllDiffs();
-    },
+    }
 
     _paramsChanged(value) {
       // Change the content of the comment tabs back to messages list, but
@@ -764,7 +785,7 @@
       this._reload(true).then(() => {
         this._performPostLoadTasks();
       });
-    },
+    }
 
     _sendShowChangeEvent() {
       this.$.jsAPI.handleEvent(this.$.jsAPI.EventType.SHOW_CHANGE, {
@@ -772,7 +793,7 @@
         patchNum: this._patchRange.patchNum,
         info: {mergeable: this._mergeable},
       });
-    },
+    }
 
     _setPrimaryTab() {
       // Selected has to be set after the paper-tabs are visible because
@@ -780,7 +801,7 @@
       this.$.commentTabs.selected = 0;
       const primaryTabs = this.$$('#primaryTabs');
       if (primaryTabs) primaryTabs.selected = 0;
-    },
+    }
 
     _performPostLoadTasks() {
       this._maybeShowReplyDialog();
@@ -799,7 +820,7 @@
         }
         this._initialLoadComplete = true;
       });
-    },
+    }
 
     _paramsAndChangeChanged(value, change) {
       // Polymer 2: check for undefined
@@ -815,16 +836,16 @@
           patchRangeState.patchNum !== this._patchRange.patchNum) {
         this._resetFileListViewState();
       }
-    },
+    }
 
     _viewStateChanged(viewState) {
       this._numFilesShown = viewState.numFilesShown ?
         viewState.numFilesShown : DEFAULT_NUM_FILES_SHOWN;
-    },
+    }
 
     _numFilesShownChanged(numFilesShown) {
       this.viewState.numFilesShown = numFilesShown;
-    },
+    }
 
     _handleMessageAnchorTap(e) {
       const hash = MSG_PREFIX + e.detail.id;
@@ -832,18 +853,18 @@
           this._patchRange.patchNum, this._patchRange.basePatchNum,
           this._editMode, hash);
       history.replaceState(null, '', url);
-    },
+    }
 
     _maybeScrollToMessage(hash) {
       if (hash.startsWith(MSG_PREFIX)) {
         this.messagesList.scrollToMessage(hash.substr(MSG_PREFIX.length));
       }
-    },
+    }
 
     _getLocationSearch() {
       // Not inlining to make it easier to test.
       return window.location.search;
-    },
+    }
 
     _getUrlParameter(param) {
       const pageURL = this._getLocationSearch().substring(1);
@@ -855,7 +876,7 @@
         }
       }
       return null;
-    },
+    }
 
     _maybeShowRevertDialog() {
       Gerrit.awaitPluginsLoaded()
@@ -871,7 +892,7 @@
               this.$.actions.showRevertDialog();
             }
           });
-    },
+    }
 
     _maybeShowReplyDialog() {
       this._getLoggedIn().then(loggedIn => {
@@ -885,7 +906,7 @@
           this.set('viewState.showReplyDialog', false);
         }
       });
-    },
+    }
 
     _resetFileListViewState() {
       this.set('viewState.selectedFileIndex', 0);
@@ -899,7 +920,7 @@
       }
       this.set('viewState.changeNum', this._changeNum);
       this.set('viewState.patchRange', this._patchRange);
-    },
+    }
 
     _changeChanged(change) {
       if (!change || !this._patchRange || !this._allPatchSets) { return; }
@@ -915,7 +936,7 @@
 
       const title = change.subject + ' (' + change.change_id.substr(0, 9) + ')';
       this.fire('title-change', {title});
-    },
+    }
 
     /**
      * Gets base patch number, if it is a parent try and decide from
@@ -947,19 +968,19 @@
       }
 
       return 'PARENT';
-    },
+    }
 
     _computeShowPrimaryTabs(dynamicTabHeaderEndpoints) {
       return dynamicTabHeaderEndpoints && dynamicTabHeaderEndpoints.length > 0;
-    },
+    }
 
     _computeChangeUrl(change) {
       return Gerrit.Nav.getUrlForChange(change);
-    },
+    }
 
     _computeShowCommitInfo(changeStatus, current_revision) {
       return changeStatus === 'Merged' && current_revision;
-    },
+    }
 
     _computeMergedCommitInfo(current_revision, revisions) {
       const rev = revisions[current_revision];
@@ -968,11 +989,11 @@
       // in <gr-commit-info>. @see Issue 5337
       if (!rev.commit.commit) { rev.commit.commit = current_revision; }
       return rev.commit;
-    },
+    }
 
     _computeChangeIdClass(displayChangeId) {
       return displayChangeId === CHANGE_ID_ERROR.MISMATCH ? 'warning' : '';
-    },
+    }
 
     _computeTitleAttributeWarning(displayChangeId) {
       if (displayChangeId === CHANGE_ID_ERROR.MISMATCH) {
@@ -980,7 +1001,7 @@
       } else if (displayChangeId === CHANGE_ID_ERROR.MISSING) {
         return 'No Change-Id in commit message';
       }
-    },
+    }
 
     _computeChangeIdCommitMessageError(commitMessage, change) {
       // Polymer 2: check for undefined
@@ -1010,11 +1031,11 @@
       }
       // There is no change-id in the commit message.
       return CHANGE_ID_ERROR.MISSING;
-    },
+    }
 
     _computeLabelNames(labels) {
       return Object.keys(labels).sort();
-    },
+    }
 
     _computeLabelValues(labelName, labels) {
       const result = [];
@@ -1039,7 +1060,7 @@
         }
       }
       return result;
-    },
+    }
 
     _computeReplyButtonLabel(changeRecord, canStartReview) {
       // Polymer 2: check for undefined
@@ -1061,7 +1082,7 @@
         label += ' (' + draftCount + ')';
       }
       return label;
-    },
+    }
 
     _handleOpenReplyDialog(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
@@ -1077,7 +1098,7 @@
         e.preventDefault();
         this._openReplyDialog(this.$.replyDialog.FocusTarget.ANY);
       });
-    },
+    }
 
     _handleOpenDownloadDialogShortcut(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
@@ -1085,7 +1106,7 @@
 
       e.preventDefault();
       this.$.downloadOverlay.open();
-    },
+    }
 
     _handleEditTopic(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
@@ -1093,13 +1114,13 @@
 
       e.preventDefault();
       this.$.metadata.editTopic();
-    },
+    }
 
     _handleRefreshChange(e) {
       if (this.shouldSuppressKeyboardShortcut(e)) { return; }
       e.preventDefault();
       Gerrit.Nav.navigateToChange(this._change);
-    },
+    }
 
     _handleToggleChangeStar(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
@@ -1107,7 +1128,7 @@
 
       e.preventDefault();
       this.$.changeStar.toggleStar();
-    },
+    }
 
     _handleUpToDashboard(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
@@ -1115,7 +1136,7 @@
 
       e.preventDefault();
       this._determinePageBack();
-    },
+    }
 
     _handleExpandAllMessages(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
@@ -1123,7 +1144,7 @@
 
       e.preventDefault();
       this.messagesList.handleExpandCollapse(true);
-    },
+    }
 
     _handleCollapseAllMessages(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
@@ -1131,7 +1152,7 @@
 
       e.preventDefault();
       this.messagesList.handleExpandCollapse(false);
-    },
+    }
 
     _handleOpenDiffPrefsShortcut(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
@@ -1141,14 +1162,14 @@
 
       e.preventDefault();
       this.$.fileList.openDiffPrefs();
-    },
+    }
 
     _determinePageBack() {
       // Default backPage to root if user came to change view page
       // via an email link, etc.
       Gerrit.Nav.navigateToRelativeUrl(this.backPage ||
           Gerrit.Nav.getUrlForRoot());
-    },
+    }
 
     _handleLabelRemoved(splices, path) {
       for (const splice of splices) {
@@ -1163,7 +1184,7 @@
           }
         }
       }
-    },
+    }
 
     _labelsChanged(changeRecord) {
       if (!changeRecord) { return; }
@@ -1174,7 +1195,7 @@
       this.$.jsAPI.handleEvent(this.$.jsAPI.EventType.LABEL_CHANGE, {
         change: this._change,
       });
-    },
+    }
 
     /**
      * @param {string=} opt_section
@@ -1186,7 +1207,7 @@
         Polymer.dom.flush();
         this.$.replyOverlay.center();
       });
-    },
+    }
 
     _handleReloadChange(e) {
       return this._reload().then(() => {
@@ -1197,19 +1218,19 @@
           Gerrit.Nav.navigateToChange(this._change);
         }
       });
-    },
+    }
 
     _handleGetChangeDetailError(response) {
       this.fire('page-error', {response});
-    },
+    }
 
     _getLoggedIn() {
       return this.$.restAPI.getLoggedIn();
-    },
+    }
 
     _getServerConfig() {
       return this.$.restAPI.getConfig();
-    },
+    }
 
     _getProjectConfig() {
       if (!this._change) return;
@@ -1217,18 +1238,18 @@
           config => {
             this._projectConfig = config;
           });
-    },
+    }
 
     _getPreferences() {
       return this.$.restAPI.getPreferences();
-    },
+    }
 
     _prepareCommitMsgForLinkify(msg) {
       // TODO(wyatta) switch linkify sequence, see issue 5526.
       // This is a zero-with space. It is added to prevent the linkify library
       // from including R= or CC= as part of the email address.
       return msg.replace(REVIEWERS_REGEX, '$1=\u200B');
-    },
+    }
 
     /**
      * Utility function to make the necessary modifications to a change in the
@@ -1258,7 +1279,7 @@
         change.revisions[edit.commit.commit].actions =
             change.revisions[edit.base_revision].actions;
       }
-    },
+    }
 
     _getChangeDetail() {
       const detailCompletes = this.$.restAPI.getChangeDetail(
@@ -1312,16 +1333,16 @@
                       parseInt(this._patchRange.patchNum, 10));
             }
           });
-    },
+    }
 
     _isSubmitEnabled(revisionActions) {
       return !!(revisionActions && revisionActions.submit &&
         revisionActions.submit.enabled);
-    },
+    }
 
     _getEdit() {
       return this.$.restAPI.getChangeEdit(this._changeNum, true);
-    },
+    }
 
     _getLatestCommitMessage() {
       return this.$.restAPI.getChangeCommitInfo(this._changeNum,
@@ -1330,7 +1351,7 @@
         this._latestCommitMessage =
                     this._prepareCommitMsgForLinkify(commitInfo.message);
       });
-    },
+    }
 
     _getLatestRevisionSHA(change) {
       if (change.current_revision) {
@@ -1349,7 +1370,7 @@
         }
       }
       return latestRev;
-    },
+    }
 
     _getCommitInfo() {
       return this.$.restAPI.getChangeCommitInfo(
@@ -1357,13 +1378,13 @@
           commitInfo => {
             this._commitInfo = commitInfo;
           });
-    },
+    }
 
     _reloadDraftsWithCallback(e) {
       return this._reloadDrafts().then(() => {
         return e.detail.resolve();
       });
-    },
+    }
 
     /**
      * Fetches a new changeComment object, and data for all types of comments
@@ -1377,7 +1398,7 @@
             this._commentThreads = this._changeComments.getAllThreadsForChange()
                 .map(c => Object.assign({}, c));
           });
-    },
+    }
 
     /**
      * Fetches a new changeComment object, but only updated data for drafts is
@@ -1389,7 +1410,7 @@
             this._changeComments = comments;
             this._diffDrafts = Object.assign({}, this._changeComments.drafts);
           });
-    },
+    }
 
     /**
      * Reload the change.
@@ -1496,7 +1517,7 @@
       });
 
       return coreDataPromise;
-    },
+    }
 
     /**
      * Kicks off requests for resources that rely on the patch range
@@ -1507,7 +1528,7 @@
         this._getCommitInfo(),
         this.$.fileList.reload(),
       ]);
-    },
+    }
 
     _getMergeability() {
       if (!this._change) {
@@ -1527,59 +1548,59 @@
       return this.$.restAPI.getMergeable(this._changeNum).then(m => {
         this._mergeable = m.mergeable;
       });
-    },
+    }
 
     _computeCanStartReview(change) {
       return !!(change.actions && change.actions.ready &&
           change.actions.ready.enabled);
-    },
+    }
 
-    _computeReplyDisabled() { return false; },
+    _computeReplyDisabled() { return false; }
 
     _computeChangePermalinkAriaLabel(changeNum) {
       return 'Change ' + changeNum;
-    },
+    }
 
     _computeCommitClass(collapsed, commitMessage) {
       if (this._computeCommitToggleHidden(commitMessage)) { return ''; }
       return collapsed ? 'collapsed' : '';
-    },
+    }
 
     _computeRelatedChangesClass(collapsed) {
       return collapsed ? 'collapsed' : '';
-    },
+    }
 
     _computeCollapseText(collapsed) {
       // Symbols are up and down triangles.
       return collapsed ? '\u25bc Show more' : '\u25b2 Show less';
-    },
+    }
 
     _toggleCommitCollapsed() {
       this._commitCollapsed = !this._commitCollapsed;
       if (this._commitCollapsed) {
         window.scrollTo(0, 0);
       }
-    },
+    }
 
     _toggleRelatedChangesCollapsed() {
       this._relatedChangesCollapsed = !this._relatedChangesCollapsed;
       if (this._relatedChangesCollapsed) {
         window.scrollTo(0, 0);
       }
-    },
+    }
 
     _computeCommitToggleHidden(commitMessage) {
       if (!commitMessage) { return true; }
       return commitMessage.split('\n').length < MIN_LINES_FOR_COMMIT_COLLAPSE;
-    },
+    }
 
     _getOffsetHeight(element) {
       return element.offsetHeight;
-    },
+    }
 
     _getScrollHeight(element) {
       return element.scrollHeight;
-    },
+    }
 
     /**
      * Get the line height of an element to the nearest integer.
@@ -1587,7 +1608,7 @@
     _getLineHeight(element) {
       const lineHeightStr = getComputedStyle(element).lineHeight;
       return Math.round(lineHeightStr.slice(0, lineHeightStr.length - 2));
-    },
+    }
 
     /**
      * New max height for the related changes section, shorter than the existing
@@ -1646,7 +1667,7 @@
       }
 
       this.updateStyles(stylesToUpdate);
-    },
+    }
 
     _computeShowRelatedToggle() {
       // Make sure the max height has been applied, since there is now content
@@ -1666,7 +1687,7 @@
         return this._showRelatedToggle = true;
       }
       this._showRelatedToggle = false;
-    },
+    }
 
     _updateToggleContainerClass(showRelatedToggle) {
       if (showRelatedToggle) {
@@ -1674,7 +1695,7 @@
       } else {
         this.$.relatedChangesToggle.classList.remove('showToggle');
       }
-    },
+    }
 
     _startUpdateCheckTimer() {
       if (!this._serverConfig ||
@@ -1717,14 +1738,14 @@
           });
         });
       }, this._serverConfig.change.update_delay * 1000);
-    },
+    }
 
     _cancelUpdateCheckTimer() {
       if (this._updateCheckTimerHandle) {
         this.cancelAsync(this._updateCheckTimerHandle);
       }
       this._updateCheckTimerHandle = null;
-    },
+    }
 
     _handleVisibilityChange() {
       if (document.hidden && this._updateCheckTimerHandle) {
@@ -1732,17 +1753,17 @@
       } else if (!this._updateCheckTimerHandle) {
         this._startUpdateCheckTimer();
       }
-    },
+    }
 
     _handleTopicChanged() {
       this.$.relatedChanges.reload();
-    },
+    }
 
     _computeHeaderClass(editMode) {
       const classes = ['header'];
       if (editMode) { classes.push('editMode'); }
       return classes.join(' ');
-    },
+    }
 
     _computeEditMode(patchRangeRecord, paramsRecord) {
       if ([patchRangeRecord, paramsRecord].some(arg => arg === undefined)) {
@@ -1753,7 +1774,7 @@
 
       const patchRange = patchRangeRecord.base || {};
       return this.patchNumEquals(patchRange.patchNum, this.EDIT_NAME);
-    },
+    }
 
     _handleFileActionTap(e) {
       e.preventDefault();
@@ -1775,11 +1796,11 @@
           controls.openRestoreDialog(path);
           break;
       }
-    },
+    }
 
     _computeCommitMessageKey(number, revision) {
       return `c${number}_rev${revision}`;
-    },
+    }
 
     _patchNumChanged(patchNumStr) {
       if (!this._selectedRevision) {
@@ -1791,7 +1812,7 @@
       }
       this._selectedRevision = Object.values(this._change.revisions).find(
           revision => revision._number === patchNum);
-    },
+    }
 
     /**
      * If an edit exists already, load it. Otherwise, toggle edit mode via the
@@ -1814,31 +1835,33 @@
         patchNum = this._patchRange.patchNum;
       }
       Gerrit.Nav.navigateToChange(this._change, patchNum, null, true);
-    },
+    }
 
     _handleStopEditTap() {
       Gerrit.Nav.navigateToChange(this._change, this._patchRange.patchNum);
-    },
+    }
 
     _resetReplyOverlayFocusStops() {
       this.$.replyOverlay.setFocusStops(this.$.replyDialog.getFocusStops());
-    },
+    }
 
     _handleToggleStar(e) {
       this.$.restAPI.saveChangeStarred(e.detail.change._number,
           e.detail.starred);
-    },
+    }
 
     _getRevisionInfo(change) {
       return new Gerrit.RevisionInfo(change);
-    },
+    }
 
     _computeCurrentRevision(currentRevision, revisions) {
       return currentRevision && revisions && revisions[currentRevision];
-    },
+    }
 
     _computeDiffPrefsDisabled(disableDiffPrefs, loggedIn) {
       return disableDiffPrefs || !loggedIn;
-    },
-  });
+    }
+  }
+
+  customElements.define(GrChangeView.is, GrChangeView);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
index 42cb976..60d459e 100644
--- a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
+++ b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
@@ -16,32 +16,40 @@
  */
 (function() {
   'use strict';
-  Polymer({
-    is: 'gr-comment-list',
 
-    behaviors: [
-      Gerrit.BaseUrlBehavior,
-      Gerrit.PathListBehavior,
-      Gerrit.URLEncodingBehavior,
-    ],
+  /**
+    * @appliesMixin Gerrit.BaseUrlMixin
+    * @appliesMixin Gerrit.PathListMixin
+    * @appliesMixin Gerrit.URLEncodingMixin
+    */
+  class GrCommentList extends Polymer.mixinBehaviors( [
+    Gerrit.BaseUrlBehavior,
+    Gerrit.PathListBehavior,
+    Gerrit.URLEncodingBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-comment-list'; }
 
-    properties: {
-      changeNum: Number,
-      comments: Object,
-      patchNum: Number,
-      projectName: String,
-      /** @type {?} */
-      projectConfig: Object,
-    },
+    static get properties() {
+      return {
+        changeNum: Number,
+        comments: Object,
+        patchNum: Number,
+        projectName: String,
+        /** @type {?} */
+        projectConfig: Object,
+      };
+    }
 
     _computeFilesFromComments(comments) {
       const arr = Object.keys(comments || {});
       return arr.sort(this.specialFilePathCompare);
-    },
+    }
 
     _isOnParent(comment) {
       return comment.side === 'PARENT';
-    },
+    }
 
     _computeDiffLineURL(file, changeNum, patchNum, comment) {
       const basePatchNum = comment.hasOwnProperty('parent') ?
@@ -49,13 +57,13 @@
       return Gerrit.Nav.getUrlForDiffById(this.changeNum, this.projectName,
           file, patchNum, basePatchNum, comment.line,
           this._isOnParent(comment));
-    },
+    }
 
     _computeCommentsForFile(comments, file) {
       // Changes are not picked up by the dom-repeat due to the array instance
       // identity not changing even when it has elements added/removed from it.
       return (comments[file] || []).slice();
-    },
+    }
 
     _computePatchDisplayName(comment) {
       if (this._isOnParent(comment)) {
@@ -65,6 +73,8 @@
         return `PS${comment.patch_set}, `;
       }
       return '';
-    },
-  });
+    }
+  }
+
+  customElements.define(GrCommentList.is, GrCommentList);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.js b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.js
index e2fcdff..2a3fe89 100644
--- a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.js
+++ b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.js
@@ -17,23 +17,27 @@
 (function() {
   'use strict';
 
-  Polymer({
-    is: 'gr-commit-info',
+  class GrCommitInfo extends Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element)) {
+    static get is() { return 'gr-commit-info'; }
 
-    properties: {
-      change: Object,
-      /** @type {?} */
-      commitInfo: Object,
-      serverConfig: Object,
-      _showWebLink: {
-        type: Boolean,
-        computed: '_computeShowWebLink(change, commitInfo, serverConfig)',
-      },
-      _webLink: {
-        type: String,
-        computed: '_computeWebLink(change, commitInfo, serverConfig)',
-      },
-    },
+    static get properties() {
+      return {
+        change: Object,
+        /** @type {?} */
+        commitInfo: Object,
+        serverConfig: Object,
+        _showWebLink: {
+          type: Boolean,
+          computed: '_computeShowWebLink(change, commitInfo, serverConfig)',
+        },
+        _webLink: {
+          type: String,
+          computed: '_computeWebLink(change, commitInfo, serverConfig)',
+        },
+      };
+    }
 
     _getWeblink(change, commitInfo, config) {
       return Gerrit.Nav.getPatchSetWeblink(
@@ -43,7 +47,7 @@
             weblinks: commitInfo.web_links,
             config,
           });
-    },
+    }
 
     _computeShowWebLink(change, commitInfo, serverConfig) {
       // Polymer 2: check for undefined
@@ -53,7 +57,7 @@
 
       const weblink = this._getWeblink(change, commitInfo, serverConfig);
       return !!weblink && !!weblink.url;
-    },
+    }
 
     _computeWebLink(change, commitInfo, serverConfig) {
       // Polymer 2: check for undefined
@@ -63,12 +67,14 @@
 
       const {url} = this._getWeblink(change, commitInfo, serverConfig) || {};
       return url;
-    },
+    }
 
     _computeShortHash(commitInfo) {
       const {name} =
             this._getWeblink(this.change, commitInfo, this.serverConfig) || {};
       return name;
-    },
-  });
+    }
+  }
+
+  customElements.define(GrCommitInfo.is, GrCommitInfo);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js
index 524876e..6ef5b69 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js
@@ -17,9 +17,17 @@
 (function() {
   'use strict';
 
-  Polymer({
-    is: 'gr-confirm-abandon-dialog',
-
+  /**
+    * @appliesMixin Gerrit.FireMixin
+    * @appliesMixin Gerrit.KeyboardShortcutMixin
+    */
+  class GrConfirmAbandonDialog extends Polymer.mixinBehaviors( [
+    Gerrit.FireBehavior,
+    Gerrit.KeyboardShortcutBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-confirm-abandon-dialog'; }
     /**
      * Fired when the confirm button is pressed.
      *
@@ -32,41 +40,42 @@
      * @event cancel
      */
 
-    properties: {
-      message: String,
-    },
+    static get properties() {
+      return {
+        message: String,
+      };
+    }
 
-    behaviors: [
-      Gerrit.FireBehavior,
-      Gerrit.KeyboardShortcutBehavior,
-    ],
-
-    keyBindings: {
-      'ctrl+enter meta+enter': '_handleEnterKey',
-    },
+    get keyBindings() {
+      return {
+        'ctrl+enter meta+enter': '_handleEnterKey',
+      };
+    }
 
     resetFocus() {
       this.$.messageInput.textarea.focus();
-    },
+    }
 
     _handleEnterKey(e) {
       this._confirm();
-    },
+    }
 
     _handleConfirmTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this._confirm();
-    },
+    }
 
     _confirm() {
       this.fire('confirm', {reason: this.message}, {bubbles: false});
-    },
+    }
 
     _handleCancelTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.fire('cancel', null, {bubbles: false});
-    },
-  });
+    }
+  }
+
+  customElements.define(GrConfirmAbandonDialog.is, GrConfirmAbandonDialog);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.js
index a0da331..669c6b1 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.js
@@ -17,12 +17,15 @@
 (function() {
   'use strict';
 
-  Polymer({
-    is: 'gr-confirm-cherrypick-conflict-dialog',
-
-    behaviors: [
-      Gerrit.FireBehavior,
-    ],
+  /**
+    * @appliesMixin Gerrit.FireMixin
+    */
+  class GrConfirmCherrypickConflictDialog extends Polymer.mixinBehaviors( [
+    Gerrit.FireBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-confirm-cherrypick-conflict-dialog'; }
 
     /**
      * Fired when the confirm button is pressed.
@@ -40,12 +43,15 @@
       e.preventDefault();
       e.stopPropagation();
       this.fire('confirm', null, {bubbles: false});
-    },
+    }
 
     _handleCancelTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.fire('cancel', null, {bubbles: false});
-    },
-  });
+    }
+  }
+
+  customElements.define(GrConfirmCherrypickConflictDialog.is,
+      GrConfirmCherrypickConflictDialog);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.js
index 5278540..bdc5c10 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.js
@@ -19,9 +19,15 @@
 
   const SUGGESTIONS_LIMIT = 15;
 
-  Polymer({
-    is: 'gr-confirm-cherrypick-dialog',
-
+  /**
+    * @appliesMixin Gerrit.FireMixin
+    */
+  class GrConfirmCherrypickDialog extends Polymer.mixinBehaviors( [
+    Gerrit.FireBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-confirm-cherrypick-dialog'; }
     /**
      * Fired when the confirm button is pressed.
      *
@@ -34,29 +40,29 @@
      * @event cancel
      */
 
-    properties: {
-      branch: String,
-      baseCommit: String,
-      changeStatus: String,
-      commitMessage: String,
-      commitNum: String,
-      message: String,
-      project: String,
-      _query: {
-        type: Function,
-        value() {
-          return this._getProjectBranchesSuggestions.bind(this);
+    static get properties() {
+      return {
+        branch: String,
+        baseCommit: String,
+        changeStatus: String,
+        commitMessage: String,
+        commitNum: String,
+        message: String,
+        project: String,
+        _query: {
+          type: Function,
+          value() {
+            return this._getProjectBranchesSuggestions.bind(this);
+          },
         },
-      },
-    },
+      };
+    }
 
-    behaviors: [
-      Gerrit.FireBehavior,
-    ],
-
-    observers: [
-      '_computeMessage(changeStatus, commitNum, commitMessage)',
-    ],
+    static get observers() {
+      return [
+        '_computeMessage(changeStatus, commitNum, commitMessage)',
+      ];
+    }
 
     _computeMessage(changeStatus, commitNum, commitMessage) {
       // Polymer 2: check for undefined
@@ -74,23 +80,23 @@
         newMessage += '(cherry picked from commit ' + commitNum + ')';
       }
       this.message = newMessage;
-    },
+    }
 
     _handleConfirmTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.fire('confirm', null, {bubbles: false});
-    },
+    }
 
     _handleCancelTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.fire('cancel', null, {bubbles: false});
-    },
+    }
 
     resetFocus() {
       this.$.branchInput.focus();
-    },
+    }
 
     _getProjectBranchesSuggestions(input) {
       if (input.startsWith('refs/heads/')) {
@@ -113,6 +119,9 @@
         }
         return branches;
       });
-    },
-  });
+    }
+  }
+
+  customElements.define(GrConfirmCherrypickDialog.is,
+      GrConfirmCherrypickDialog);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.js
index c6b0adf..fb78bfb 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.js
@@ -19,9 +19,15 @@
 
   const SUGGESTIONS_LIMIT = 15;
 
-  Polymer({
-    is: 'gr-confirm-move-dialog',
-
+  /**
+    * @appliesMixin Gerrit.FireMixin
+    */
+  class GrConfirmMoveDialog extends Polymer.mixinBehaviors( [
+    Gerrit.FireBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-confirm-move-dialog'; }
     /**
      * Fired when the confirm button is pressed.
      *
@@ -34,33 +40,31 @@
      * @event cancel
      */
 
-    properties: {
-      branch: String,
-      message: String,
-      project: String,
-      _query: {
-        type: Function,
-        value() {
-          return this._getProjectBranchesSuggestions.bind(this);
+    static get properties() {
+      return {
+        branch: String,
+        message: String,
+        project: String,
+        _query: {
+          type: Function,
+          value() {
+            return this._getProjectBranchesSuggestions.bind(this);
+          },
         },
-      },
-    },
-
-    behaviors: [
-      Gerrit.FireBehavior,
-    ],
+      };
+    }
 
     _handleConfirmTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.fire('confirm', null, {bubbles: false});
-    },
+    }
 
     _handleCancelTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.fire('cancel', null, {bubbles: false});
-    },
+    }
 
     _getProjectBranchesSuggestions(input) {
       if (input.startsWith('refs/heads/')) {
@@ -83,6 +87,8 @@
         }
         return branches;
       });
-    },
-  });
+    }
+  }
+
+  customElements.define(GrConfirmMoveDialog.is, GrConfirmMoveDialog);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js
index 54ce271..7169437 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js
@@ -17,9 +17,10 @@
 (function() {
   'use strict';
 
-  Polymer({
-    is: 'gr-confirm-rebase-dialog',
-
+  class GrConfirmRebaseDialog extends Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element)) {
+    static get is() { return 'gr-confirm-rebase-dialog'; }
     /**
      * Fired when the confirm button is pressed.
      *
@@ -32,24 +33,28 @@
      * @event cancel
      */
 
-    properties: {
-      branch: String,
-      changeNumber: Number,
-      hasParent: Boolean,
-      rebaseOnCurrent: Boolean,
-      _text: String,
-      _query: {
-        type: Function,
-        value() {
-          return this._getChangeSuggestions.bind(this);
+    static get properties() {
+      return {
+        branch: String,
+        changeNumber: Number,
+        hasParent: Boolean,
+        rebaseOnCurrent: Boolean,
+        _text: String,
+        _query: {
+          type: Function,
+          value() {
+            return this._getChangeSuggestions.bind(this);
+          },
         },
-      },
-      _recentChanges: Array,
-    },
+        _recentChanges: Array,
+      };
+    }
 
-    observers: [
-      '_updateSelectedOption(rebaseOnCurrent, hasParent)',
-    ],
+    static get observers() {
+      return [
+        '_updateSelectedOption(rebaseOnCurrent, hasParent)',
+      ];
+    }
 
     // This is called by gr-change-actions every time the rebase dialog is
     // re-opened. Unlike other autocompletes that make a request with each
@@ -71,36 +76,36 @@
             this._recentChanges = changes;
             return this._recentChanges;
           });
-    },
+    }
 
     _getRecentChanges() {
       if (this._recentChanges) {
         return Promise.resolve(this._recentChanges);
       }
       return this.fetchRecentChanges();
-    },
+    }
 
     _getChangeSuggestions(input) {
       return this._getRecentChanges().then(changes =>
         this._filterChanges(input, changes));
-    },
+    }
 
     _filterChanges(input, changes) {
       return changes.filter(change => change.name.includes(input) &&
           change.value !== this.changeNumber);
-    },
+    }
 
     _displayParentOption(rebaseOnCurrent, hasParent) {
       return hasParent && rebaseOnCurrent;
-    },
+    }
 
     _displayParentUpToDateMsg(rebaseOnCurrent, hasParent) {
       return hasParent && !rebaseOnCurrent;
-    },
+    }
 
     _displayTipOption(rebaseOnCurrent, hasParent) {
       return !(!rebaseOnCurrent && !hasParent);
-    },
+    }
 
     /**
      * There is a subtle but important difference between setting the base to an
@@ -115,7 +120,7 @@
       // Change numbers will have their description appended by the
       // autocomplete.
       return this._text.split(':')[0];
-    },
+    }
 
     _handleConfirmTap(e) {
       e.preventDefault();
@@ -123,22 +128,22 @@
       this.dispatchEvent(new CustomEvent('confirm',
           {detail: {base: this._getSelectedBase()}}));
       this._text = '';
-    },
+    }
 
     _handleCancelTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.dispatchEvent(new CustomEvent('cancel'));
       this._text = '';
-    },
+    }
 
     _handleRebaseOnOther() {
       this.$.parentInput.focus();
-    },
+    }
 
     _handleEnterChangeNumberClick() {
       this.$.rebaseOnOtherInput.checked = true;
-    },
+    }
 
     /**
      * Sets the default radio button based on the state of the app and
@@ -157,6 +162,8 @@
       } else {
         this.$.rebaseOnOtherInput.checked = true;
       }
-    },
-  });
+    }
+  }
+
+  customElements.define(GrConfirmRebaseDialog.is, GrConfirmRebaseDialog);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.js
index 662b64c..e95f2c9 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.js
@@ -20,9 +20,15 @@
   const ERR_COMMIT_NOT_FOUND =
       'Unable to find the commit hash of this change.';
 
-  Polymer({
-    is: 'gr-confirm-revert-dialog',
-
+  /**
+    * @appliesMixin Gerrit.FireMixin
+    */
+  class GrConfirmRevertDialog extends Polymer.mixinBehaviors( [
+    Gerrit.FireBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-confirm-revert-dialog'; }
     /**
      * Fired when the confirm button is pressed.
      *
@@ -35,13 +41,11 @@
      * @event cancel
      */
 
-    properties: {
-      message: String,
-    },
-
-    behaviors: [
-      Gerrit.FireBehavior,
-    ],
+    static get properties() {
+      return {
+        message: String,
+      };
+    }
 
     populateRevertMessage(message, commitHash) {
       // Figure out what the revert title should be.
@@ -55,18 +59,20 @@
 
       this.message = `${revertTitle}\n\n${revertCommitText}\n\n` +
           `Reason for revert: <INSERT REASONING HERE>\n`;
-    },
+    }
 
     _handleConfirmTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.fire('confirm', null, {bubbles: false});
-    },
+    }
 
     _handleCancelTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.fire('cancel', null, {bubbles: false});
-    },
-  });
+    }
+  }
+
+  customElements.define(GrConfirmRevertDialog.is, GrConfirmRevertDialog);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.js
index 6cbbb37..04b16ee 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.js
@@ -20,9 +20,15 @@
   const ERR_COMMIT_NOT_FOUND =
       'Unable to find the commit hash of this change.';
 
-  Polymer({
-    is: 'gr-confirm-revert-submission-dialog',
-
+  /**
+    * @appliesMixin Gerrit.FireMixin
+    */
+  class GrConfirmRevertSubmissionDialog extends Polymer.mixinBehaviors( [
+    Gerrit.FireBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-confirm-revert-submission-dialog'; }
     /**
      * Fired when the confirm button is pressed.
      *
@@ -35,13 +41,11 @@
      * @event cancel
      */
 
-    properties: {
-      message: String,
-    },
-
-    behaviors: [
-      Gerrit.FireBehavior,
-    ],
+    static get properties() {
+      return {
+        message: String,
+      };
+    }
 
     populateRevertSubmissionMessage(message, commitHash) {
       // Follow the same convention of the revert
@@ -52,18 +56,21 @@
       }
       this.message = `${revertTitle}\n\n` +
           `Reason for revert: <INSERT REASONING HERE>\n`;
-    },
+    }
 
     _handleConfirmTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.fire('confirm', null, {bubbles: false});
-    },
+    }
 
     _handleCancelTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.fire('cancel', null, {bubbles: false});
-    },
-  });
+    }
+  }
+
+  customElements.define(GrConfirmRevertSubmissionDialog.is,
+      GrConfirmRevertSubmissionDialog);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.js
index e86e21c..05841e9 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.js
@@ -17,9 +17,10 @@
 (function() {
   'use strict';
 
-  Polymer({
-    is: 'gr-confirm-submit-dialog',
-
+  class GrConfirmSubmitDialog extends Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element)) {
+    static get is() { return 'gr-confirm-submit-dialog'; }
     /**
      * Fired when the confirm button is pressed.
      *
@@ -32,37 +33,41 @@
      * @event cancel
      */
 
-    properties: {
+    static get properties() {
+      return {
       /**
        * @type {{
        *    is_private: boolean,
        *    subject: string,
        *  }}
        */
-      change: Object,
+        change: Object,
 
-      /**
+        /**
        * @type {{
        *    label: string,
        *  }}
        */
-      action: Object,
-    },
+        action: Object,
+      };
+    }
 
     resetFocus(e) {
       this.$.dialog.resetFocus();
-    },
+    }
 
     _handleConfirmTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.dispatchEvent(new CustomEvent('confirm', {bubbles: false}));
-    },
+    }
 
     _handleCancelTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.dispatchEvent(new CustomEvent('cancel', {bubbles: false}));
-    },
-  });
+    }
+  }
+
+  customElements.define(GrConfirmSubmitDialog.is, GrConfirmSubmitDialog);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
index b2e5e63..ab849de 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
@@ -17,40 +17,47 @@
 (function() {
   'use strict';
 
-  Polymer({
-    is: 'gr-download-dialog',
-
+  /**
+    * @appliesMixin Gerrit.FireMixin
+    * @appliesMixin Gerrit.PatchSetMixin
+    * @appliesMixin Gerrit.RESTClientMixin
+    */
+  class GrDownloadDialog extends Polymer.mixinBehaviors( [
+    Gerrit.FireBehavior,
+    Gerrit.PatchSetBehavior,
+    Gerrit.RESTClientBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-download-dialog'; }
     /**
      * Fired when the user presses the close button.
      *
      * @event close
      */
 
-    properties: {
+    static get properties() {
+      return {
       /** @type {{ revisions: Array }} */
-      change: Object,
-      patchNum: String,
-      /** @type {?} */
-      config: Object,
+        change: Object,
+        patchNum: String,
+        /** @type {?} */
+        config: Object,
 
-      _schemes: {
-        type: Array,
-        value() { return []; },
-        computed: '_computeSchemes(change, patchNum)',
-        observer: '_schemesChanged',
-      },
-      _selectedScheme: String,
-    },
+        _schemes: {
+          type: Array,
+          value() { return []; },
+          computed: '_computeSchemes(change, patchNum)',
+          observer: '_schemesChanged',
+        },
+        _selectedScheme: String,
+      };
+    }
 
-    hostAttributes: {
-      role: 'dialog',
-    },
-
-    behaviors: [
-      Gerrit.FireBehavior,
-      Gerrit.PatchSetBehavior,
-      Gerrit.RESTClientBehavior,
-    ],
+    ready() {
+      super.ready();
+      this._ensureAttribute('role', 'dialog');
+    }
 
     focus() {
       if (this._schemes.length) {
@@ -58,7 +65,7 @@
       } else {
         this.$.download.focus();
       }
-    },
+    }
 
     getFocusStops() {
       const links = this.$$('#archives').querySelectorAll('a');
@@ -66,7 +73,7 @@
         start: this.$.closeButton,
         end: links[links.length - 1],
       };
-    },
+    }
 
     _computeDownloadCommands(change, patchNum, _selectedScheme) {
       let commandObj;
@@ -87,7 +94,7 @@
         });
       }
       return commands;
-    },
+    }
 
     /**
      * @param {!Object} change
@@ -97,7 +104,7 @@
      */
     _computeZipDownloadLink(change, patchNum) {
       return this._computeDownloadLink(change, patchNum, true);
-    },
+    }
 
     /**
      * @param {!Object} change
@@ -107,7 +114,7 @@
      */
     _computeZipDownloadFilename(change, patchNum) {
       return this._computeDownloadFilename(change, patchNum, true);
-    },
+    }
 
     /**
      * @param {!Object} change
@@ -123,7 +130,7 @@
       }
       return this.changeBaseURL(change.project, change._number, patchNum) +
           '/patch?' + (opt_zip ? 'zip' : 'download');
-    },
+    }
 
     /**
      * @param {!Object} change
@@ -146,7 +153,7 @@
         }
       }
       return shortRev + '.diff.' + (opt_zip ? 'zip' : 'base64');
-    },
+    }
 
     _computeHidePatchFile(change, patchNum) {
       // Polymer 2: check for undefined
@@ -161,7 +168,7 @@
         }
       }
       return false;
-    },
+    }
 
     _computeArchiveDownloadLink(change, patchNum, format) {
       // Polymer 2: check for undefined
@@ -170,7 +177,7 @@
       }
       return this.changeBaseURL(change.project, change._number, patchNum) +
           '/archive?format=' + format;
-    },
+    }
 
     _computeSchemes(change, patchNum) {
       // Polymer 2: check for undefined
@@ -188,28 +195,30 @@
         }
       }
       return [];
-    },
+    }
 
     _computePatchSetQuantity(revisions) {
       if (!revisions) { return 0; }
       return Object.keys(revisions).length;
-    },
+    }
 
     _handleCloseTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.fire('close', null, {bubbles: false});
-    },
+    }
 
     _schemesChanged(schemes) {
       if (schemes.length === 0) { return; }
       if (!schemes.includes(this._selectedScheme)) {
         this._selectedScheme = schemes.sort()[0];
       }
-    },
+    }
 
     _computeShowDownloadCommands(schemes) {
       return schemes.length ? '' : 'hidden';
-    },
-  });
+    }
+  }
+
+  customElements.define(GrDownloadDialog.is, GrDownloadDialog);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js
index b8095bf..dded147 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js
@@ -21,9 +21,17 @@
   const PATCH_DESC_MAX_LENGTH = 500;
   const MERGED_STATUS = 'MERGED';
 
-  Polymer({
-    is: 'gr-file-list-header',
-
+  /**
+    * @appliesMixin Gerrit.FireMixin
+    * @appliesMixin Gerrit.PatchSetMixin
+    */
+  class GrFileListHeader extends Polymer.mixinBehaviors( [
+    Gerrit.FireBehavior,
+    Gerrit.PatchSetBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-file-list-header'; }
     /**
      * @event expand-diffs
      */
@@ -48,72 +56,71 @@
      * @event open-upload-help-dialog
      */
 
-    properties: {
-      account: Object,
-      allPatchSets: Array,
-      /** @type {?} */
-      change: Object,
-      changeNum: String,
-      changeUrl: String,
-      changeComments: Object,
-      commitInfo: Object,
-      editMode: Boolean,
-      loggedIn: Boolean,
-      serverConfig: Object,
-      shownFileCount: Number,
-      diffPrefs: Object,
-      diffPrefsDisabled: Boolean,
-      diffViewMode: {
-        type: String,
-        notify: true,
-      },
-      patchNum: String,
-      basePatchNum: String,
-      filesExpanded: String,
-      // Caps the number of files that can be shown and have the 'show diffs' /
-      // 'hide diffs' buttons still be functional.
-      _maxFilesForBulkActions: {
-        type: Number,
-        readOnly: true,
-        value: 225,
-      },
-      _patchsetDescription: {
-        type: String,
-        value: '',
-      },
-      showTitle: {
-        type: Boolean,
-        value: true,
-      },
-      _descriptionReadOnly: {
-        type: Boolean,
-        computed: '_computeDescriptionReadOnly(loggedIn, change, account)',
-      },
-      revisionInfo: Object,
-    },
+    static get properties() {
+      return {
+        account: Object,
+        allPatchSets: Array,
+        /** @type {?} */
+        change: Object,
+        changeNum: String,
+        changeUrl: String,
+        changeComments: Object,
+        commitInfo: Object,
+        editMode: Boolean,
+        loggedIn: Boolean,
+        serverConfig: Object,
+        shownFileCount: Number,
+        diffPrefs: Object,
+        diffPrefsDisabled: Boolean,
+        diffViewMode: {
+          type: String,
+          notify: true,
+        },
+        patchNum: String,
+        basePatchNum: String,
+        filesExpanded: String,
+        // Caps the number of files that can be shown and have the 'show diffs' /
+        // 'hide diffs' buttons still be functional.
+        _maxFilesForBulkActions: {
+          type: Number,
+          readOnly: true,
+          value: 225,
+        },
+        _patchsetDescription: {
+          type: String,
+          value: '',
+        },
+        showTitle: {
+          type: Boolean,
+          value: true,
+        },
+        _descriptionReadOnly: {
+          type: Boolean,
+          computed: '_computeDescriptionReadOnly(loggedIn, change, account)',
+        },
+        revisionInfo: Object,
+      };
+    }
 
-    behaviors: [
-      Gerrit.FireBehavior,
-      Gerrit.PatchSetBehavior,
-    ],
-
-    observers: [
-      '_computePatchSetDescription(change, patchNum)',
-    ],
+    static get observers() {
+      return [
+        '_computePatchSetDescription(change, patchNum)',
+      ];
+    }
 
     setDiffViewMode(mode) {
       this.$.modeSelect.setMode(mode);
-    },
+    }
 
     _expandAllDiffs() {
       this._expanded = true;
       this.fire('expand-diffs');
-    },
+    }
 
     _collapseAllDiffs() {
       this._expanded = false;
       this.fire('collapse-diffs');
-    },
+    }
 
     _computeExpandedClass(filesExpanded) {
       const classes = [];
@@ -125,11 +132,11 @@
         classes.push('openFile');
       }
       return classes.join(' ');
-    },
+    }
 
     _computeDescriptionPlaceholder(readOnly) {
       return (readOnly ? 'No' : 'Add') + ' patchset description';
-    },
+    }
 
     _computeDescriptionReadOnly(loggedIn, change, account) {
       // Polymer 2: check for undefined
@@ -138,7 +145,7 @@
       }
 
       return !(loggedIn && (account._account_id === change.owner._account_id));
-    },
+    }
 
     _computePatchSetDescription(change, patchNum) {
       // Polymer 2: check for undefined
@@ -149,11 +156,11 @@
       const rev = this.getRevisionByPatchNum(change.revisions, patchNum);
       this._patchsetDescription = (rev && rev.description) ?
         rev.description.substring(0, PATCH_DESC_MAX_LENGTH) : '';
-    },
+    }
 
     _handleDescriptionRemoved(e) {
       return this._updateDescription('', e);
-    },
+    }
 
     /**
      * @param {!Object} revisions The revisions object keyed by revision hashes
@@ -167,12 +174,12 @@
           return rev;
         }
       }
-    },
+    }
 
     _handleDescriptionChanged(e) {
       const desc = e.detail.trim();
       this._updateDescription(desc, e);
-    },
+    }
 
     /**
      * Update the patchset description with the rest API.
@@ -197,43 +204,43 @@
             if (target) { target.disabled = false; }
             return;
           });
-    },
+    }
 
     _computePrefsButtonHidden(prefs, diffPrefsDisabled) {
       return diffPrefsDisabled || !prefs;
-    },
+    }
 
     _fileListActionsVisible(shownFileCount, maxFilesForBulkActions) {
       return shownFileCount <= maxFilesForBulkActions;
-    },
+    }
 
     _handlePatchChange(e) {
       const {basePatchNum, patchNum} = e.detail;
       if (this.patchNumEquals(basePatchNum, this.basePatchNum) &&
           this.patchNumEquals(patchNum, this.patchNum)) { return; }
       Gerrit.Nav.navigateToChange(this.change, patchNum, basePatchNum);
-    },
+    }
 
     _handlePrefsTap(e) {
       e.preventDefault();
       this.fire('open-diff-prefs');
-    },
+    }
 
     _handleIncludedInTap(e) {
       e.preventDefault();
       this.fire('open-included-in-dialog');
-    },
+    }
 
     _handleDownloadTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.dispatchEvent(
           new CustomEvent('open-download-dialog', {bubbles: false}));
-    },
+    }
 
     _computeEditModeClass(editMode) {
       return editMode ? 'editMode' : '';
-    },
+    }
 
     _computePatchInfoClass(patchNum, allPatchSets) {
       const latestNum = this.computeLatestPatchNum(allPatchSets);
@@ -241,18 +248,18 @@
         return '';
       }
       return 'patchInfoOldPatchSet';
-    },
+    }
 
     _hideIncludedIn(change) {
       return change && change.status === MERGED_STATUS ? '' : 'hide';
-    },
+    }
 
     _handleUploadTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.dispatchEvent(
           new CustomEvent('open-upload-help-dialog', {bubbles: false}));
-    },
+    }
 
     _computeUploadHelpContainerClass(change, account) {
       const changeIsMerged = change && change.status === MERGED_STATUS;
@@ -262,6 +269,8 @@
       const userIsOwner = ownerId && userId && ownerId === userId;
       const hideContainer = !userIsOwner || changeIsMerged;
       return 'uploadContainer desktop' + (hideContainer ? ' hide' : '');
-    },
-  });
+    }
+  }
+
+  customElements.define(GrFileListHeader.is, GrFileListHeader);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
index 6d1e376..fb57164 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
@@ -41,162 +41,175 @@
     U: 'Unchanged',
   };
 
-  Polymer({
-    is: 'gr-file-list',
-
+  /**
+    * @appliesMixin Gerrit.AsyncForeachMixin
+    * @appliesMixin Gerrit.DomUtilMixin
+    * @appliesMixin Gerrit.FireMixin
+    * @appliesMixin Gerrit.KeyboardShortcutMixin
+    * @appliesMixin Gerrit.PatchSetMixin
+    * @appliesMixin Gerrit.PathListMixin
+    */
+  class GrFileList extends Polymer.mixinBehaviors( [
+    Gerrit.AsyncForeachBehavior,
+    Gerrit.DomUtilBehavior,
+    Gerrit.FireBehavior,
+    Gerrit.KeyboardShortcutBehavior,
+    Gerrit.PatchSetBehavior,
+    Gerrit.PathListBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-file-list'; }
     /**
      * Fired when a draft refresh should get triggered
      *
      * @event reload-drafts
      */
 
-    properties: {
+    static get properties() {
+      return {
       /** @type {?} */
-      patchRange: Object,
-      patchNum: String,
-      changeNum: String,
-      /** @type {?} */
-      changeComments: Object,
-      drafts: Object,
-      revisions: Array,
-      projectConfig: Object,
-      selectedIndex: {
-        type: Number,
-        notify: true,
-      },
-      keyEventTarget: {
-        type: Object,
-        value() { return document.body; },
-      },
-      /** @type {?} */
-      change: Object,
-      diffViewMode: {
-        type: String,
-        notify: true,
-        observer: '_updateDiffPreferences',
-      },
-      editMode: {
-        type: Boolean,
-        observer: '_editModeChanged',
-      },
-      filesExpanded: {
-        type: String,
-        value: GrFileListConstants.FilesExpandedState.NONE,
-        notify: true,
-      },
-      _filesByPath: Object,
-      _files: {
-        type: Array,
-        observer: '_filesChanged',
-        value() { return []; },
-      },
-      _loggedIn: {
-        type: Boolean,
-        value: false,
-      },
-      _reviewed: {
-        type: Array,
-        value() { return []; },
-      },
-      diffPrefs: {
-        type: Object,
-        notify: true,
-        observer: '_updateDiffPreferences',
-      },
-      /** @type {?} */
-      _userPrefs: Object,
-      _showInlineDiffs: Boolean,
-      numFilesShown: {
-        type: Number,
-        notify: true,
-      },
-      /** @type {?} */
-      _patchChange: {
-        type: Object,
-        computed: '_calculatePatchChange(_files)',
-      },
-      fileListIncrement: Number,
-      _hideChangeTotals: {
-        type: Boolean,
-        computed: '_shouldHideChangeTotals(_patchChange)',
-      },
-      _hideBinaryChangeTotals: {
-        type: Boolean,
-        computed: '_shouldHideBinaryChangeTotals(_patchChange)',
-      },
+        patchRange: Object,
+        patchNum: String,
+        changeNum: String,
+        /** @type {?} */
+        changeComments: Object,
+        drafts: Object,
+        revisions: Array,
+        projectConfig: Object,
+        selectedIndex: {
+          type: Number,
+          notify: true,
+        },
+        keyEventTarget: {
+          type: Object,
+          value() { return document.body; },
+        },
+        /** @type {?} */
+        change: Object,
+        diffViewMode: {
+          type: String,
+          notify: true,
+          observer: '_updateDiffPreferences',
+        },
+        editMode: {
+          type: Boolean,
+          observer: '_editModeChanged',
+        },
+        filesExpanded: {
+          type: String,
+          value: GrFileListConstants.FilesExpandedState.NONE,
+          notify: true,
+        },
+        _filesByPath: Object,
+        _files: {
+          type: Array,
+          observer: '_filesChanged',
+          value() { return []; },
+        },
+        _loggedIn: {
+          type: Boolean,
+          value: false,
+        },
+        _reviewed: {
+          type: Array,
+          value() { return []; },
+        },
+        diffPrefs: {
+          type: Object,
+          notify: true,
+          observer: '_updateDiffPreferences',
+        },
+        /** @type {?} */
+        _userPrefs: Object,
+        _showInlineDiffs: Boolean,
+        numFilesShown: {
+          type: Number,
+          notify: true,
+        },
+        /** @type {?} */
+        _patchChange: {
+          type: Object,
+          computed: '_calculatePatchChange(_files)',
+        },
+        fileListIncrement: Number,
+        _hideChangeTotals: {
+          type: Boolean,
+          computed: '_shouldHideChangeTotals(_patchChange)',
+        },
+        _hideBinaryChangeTotals: {
+          type: Boolean,
+          computed: '_shouldHideBinaryChangeTotals(_patchChange)',
+        },
 
-      _shownFiles: {
-        type: Array,
-        computed: '_computeFilesShown(numFilesShown, _files)',
-      },
+        _shownFiles: {
+          type: Array,
+          computed: '_computeFilesShown(numFilesShown, _files)',
+        },
 
-      /**
+        /**
        * The amount of files added to the shown files list the last time it was
        * updated. This is used for reporting the average render time.
        */
-      _reportinShownFilesIncrement: Number,
+        _reportinShownFilesIncrement: Number,
 
-      _expandedFilePaths: {
-        type: Array,
-        value() { return []; },
-      },
-      _displayLine: Boolean,
-      _loading: {
-        type: Boolean,
-        observer: '_loadingChanged',
-      },
-      /** @type {Gerrit.LayoutStats|undefined} */
-      _sizeBarLayout: {
-        type: Object,
-        computed: '_computeSizeBarLayout(_shownFiles.*)',
-      },
+        _expandedFilePaths: {
+          type: Array,
+          value() { return []; },
+        },
+        _displayLine: Boolean,
+        _loading: {
+          type: Boolean,
+          observer: '_loadingChanged',
+        },
+        /** @type {Gerrit.LayoutStats|undefined} */
+        _sizeBarLayout: {
+          type: Object,
+          computed: '_computeSizeBarLayout(_shownFiles.*)',
+        },
 
-      _showSizeBars: {
-        type: Boolean,
-        value: true,
-        computed: '_computeShowSizeBars(_userPrefs)',
-      },
+        _showSizeBars: {
+          type: Boolean,
+          value: true,
+          computed: '_computeShowSizeBars(_userPrefs)',
+        },
 
-      /** @type {Function} */
-      _cancelForEachDiff: Function,
+        /** @type {Function} */
+        _cancelForEachDiff: Function,
 
-      _showDynamicColumns: {
-        type: Boolean,
-        computed: '_computeShowDynamicColumns(_dynamicHeaderEndpoints, ' +
+        _showDynamicColumns: {
+          type: Boolean,
+          computed: '_computeShowDynamicColumns(_dynamicHeaderEndpoints, ' +
                   '_dynamicContentEndpoints, _dynamicSummaryEndpoints)',
-      },
-      /** @type {Array<string>} */
-      _dynamicHeaderEndpoints: {
-        type: Array,
-      },
-      /** @type {Array<string>} */
-      _dynamicContentEndpoints: {
-        type: Array,
-      },
-      /** @type {Array<string>} */
-      _dynamicSummaryEndpoints: {
-        type: Array,
-      },
-    },
+        },
+        /** @type {Array<string>} */
+        _dynamicHeaderEndpoints: {
+          type: Array,
+        },
+        /** @type {Array<string>} */
+        _dynamicContentEndpoints: {
+          type: Array,
+        },
+        /** @type {Array<string>} */
+        _dynamicSummaryEndpoints: {
+          type: Array,
+        },
+      };
+    }
 
-    behaviors: [
-      Gerrit.AsyncForeachBehavior,
-      Gerrit.DomUtilBehavior,
-      Gerrit.FireBehavior,
-      Gerrit.KeyboardShortcutBehavior,
-      Gerrit.PatchSetBehavior,
-      Gerrit.PathListBehavior,
-    ],
-
-    observers: [
-      '_expandedPathsChanged(_expandedFilePaths.splices)',
-      '_computeFiles(_filesByPath, changeComments, patchRange, _reviewed, ' +
+    static get observers() {
+      return [
+        '_expandedPathsChanged(_expandedFilePaths.splices)',
+        '_computeFiles(_filesByPath, changeComments, patchRange, _reviewed, ' +
           '_loading)',
-    ],
+      ];
+    }
 
-    keyBindings: {
-      esc: '_handleEscKey',
-    },
+    get keyBindings() {
+      return {
+        esc: '_handleEscKey',
+      };
+    }
 
     keyboardShortcuts() {
       return {
@@ -221,12 +234,16 @@
         [this.Shortcut.EXPAND_ALL_COMMENT_THREADS]: null,
         [this.Shortcut.COLLAPSE_ALL_COMMENT_THREADS]: null,
       };
-    },
-    listeners: {
-      keydown: '_scopedKeydownHandler',
-    },
+    }
+
+    created() {
+      super.created();
+      this.addEventListener('keydown',
+          e => this._scopedKeydownHandler(e));
+    }
 
     attached() {
+      super.attached();
       Gerrit.awaitPluginsLoaded().then(() => {
         this._dynamicHeaderEndpoints = Gerrit._endpoints.getDynamicEndpoints(
             'change-view-file-list-header');
@@ -246,11 +263,12 @@
               'Different number of dynamic file-list headers and summary.');
         }
       });
-    },
+    }
 
     detached() {
+      super.detached();
       this._cancelDiffs();
-    },
+    }
 
     /**
      * Iron-a11y-keys-behavior catches keyboard events globally. Some keyboard
@@ -264,7 +282,7 @@
         // Enter.
         this._handleOpenFile(e);
       }
-    },
+    }
 
     reload() {
       if (!this.changeNum || !this.patchRange.patchNum) {
@@ -302,23 +320,23 @@
         this._detectChromiteButler();
         this.$.reporting.fileListDisplayed();
       });
-    },
+    }
 
     _detectChromiteButler() {
       const hasButler = !!document.getElementById('butler-suggested-owners');
       if (hasButler) {
         this.$.reporting.reportExtension('butler');
       }
-    },
+    }
 
     get diffs() {
       return Array.from(
           Polymer.dom(this.root).querySelectorAll('gr-diff-host'));
-    },
+    }
 
     openDiffPrefs() {
       this.$.diffPreferencesDialog.open();
-    },
+    }
 
     _calculatePatchChange(files) {
       const magicFilesExcluded = files.filter(files => {
@@ -343,15 +361,15 @@
         };
       }, {inserted: 0, deleted: 0, size_delta_inserted: 0,
         size_delta_deleted: 0, total_size: 0});
-    },
+    }
 
     _getDiffPreferences() {
       return this.$.restAPI.getDiffPreferences();
-    },
+    }
 
     _getPreferences() {
       return this.$.restAPI.getPreferences();
-    },
+    }
 
     _togglePathExpanded(path) {
       // Is the path in the list of expanded diffs? IF so remove it, otherwise
@@ -362,11 +380,11 @@
       } else {
         this.splice('_expandedFilePaths', pathIndex, 1);
       }
-    },
+    }
 
     _togglePathExpandedByIndex(index) {
       this._togglePathExpanded(this._files[index].__path);
-    },
+    }
 
     _updateDiffPreferences() {
       if (!this.diffs.length) { return; }
@@ -374,14 +392,14 @@
       this.$.reporting.time(EXPAND_ALL_TIMING_LABEL);
       this._renderInOrder(this._expandedFilePaths, this.diffs,
           this._expandedFilePaths.length);
-    },
+    }
 
     _forEachDiff(fn) {
       const diffs = this.diffs;
       for (let i = 0; i < diffs.length; i++) {
         fn(diffs[i]);
       }
-    },
+    }
 
     expandAllDiffs() {
       this._showInlineDiffs = true;
@@ -398,7 +416,7 @@
       }
 
       this.splice(...['_expandedFilePaths', 0, 0].concat(newPaths));
-    },
+    }
 
     collapseAllDiffs() {
       this._showInlineDiffs = false;
@@ -406,7 +424,7 @@
       this.filesExpanded = this._computeExpandedFiles(
           this._expandedFilePaths.length, this._files.length);
       this.$.diffCursor.handleDiffUpdate();
-    },
+    }
 
     /**
      * Computes a string with the number of comments and unresolved comments.
@@ -433,7 +451,7 @@
           (commentString && unresolvedString ? ' ' : '') +
           // Add parentheses around unresolved if it exists.
           (unresolvedString ? `(${unresolvedString})` : '');
-    },
+    }
 
     /**
      * Computes a string with the number of drafts.
@@ -448,7 +466,7 @@
           changeComments.computeDraftCount(patchRange.basePatchNum, path) +
           changeComments.computeDraftCount(patchRange.patchNum, path);
       return GrCountStringFormatter.computePluralString(draftCount, 'draft');
-    },
+    }
 
     /**
      * Computes a shortened string with the number of drafts.
@@ -463,7 +481,7 @@
           changeComments.computeDraftCount(patchRange.basePatchNum, path) +
           changeComments.computeDraftCount(patchRange.patchNum, path);
       return GrCountStringFormatter.computeShortString(draftCount, 'd');
-    },
+    }
 
     /**
      * Computes a shortened string with the number of comments.
@@ -478,7 +496,7 @@
           changeComments.computeCommentCount(patchRange.basePatchNum, path) +
           changeComments.computeCommentCount(patchRange.patchNum, path);
       return GrCountStringFormatter.computeShortString(commentCount, 'c');
-    },
+    }
 
     /**
      * @param {string} path
@@ -495,27 +513,27 @@
       }
 
       this._saveReviewedState(path, reviewed);
-    },
+    }
 
     _saveReviewedState(path, reviewed) {
       return this.$.restAPI.saveFileReviewed(this.changeNum,
           this.patchRange.patchNum, path, reviewed);
-    },
+    }
 
     _getLoggedIn() {
       return this.$.restAPI.getLoggedIn();
-    },
+    }
 
     _getReviewedFiles() {
       if (this.editMode) { return Promise.resolve([]); }
       return this.$.restAPI.getReviewedFiles(this.changeNum,
           this.patchRange.patchNum);
-    },
+    }
 
     _getFiles() {
       return this.$.restAPI.getChangeOrEditFiles(
           this.changeNum, this.patchRange);
-    },
+    }
 
     /**
      * The closure compiler doesn't realize this.specialFilePathCompare is
@@ -534,7 +552,7 @@
         files.push(info);
       }
       return files;
-    },
+    }
 
     /**
      * Handle all events from the file list dom-repeat so event handleers don't
@@ -564,7 +582,7 @@
 
       e.preventDefault();
       this._togglePathExpanded(path);
-    },
+    }
 
     _handleLeftPane(e) {
       if (this.shouldSuppressKeyboardShortcut(e) || this._noDiffsExpanded()) {
@@ -573,7 +591,7 @@
 
       e.preventDefault();
       this.$.diffCursor.moveLeft();
-    },
+    }
 
     _handleRightPane(e) {
       if (this.shouldSuppressKeyboardShortcut(e) || this._noDiffsExpanded()) {
@@ -582,7 +600,7 @@
 
       e.preventDefault();
       this.$.diffCursor.moveRight();
-    },
+    }
 
     _handleToggleInlineDiff(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
@@ -591,14 +609,14 @@
 
       e.preventDefault();
       this._togglePathExpandedByIndex(this.$.fileCursor.index);
-    },
+    }
 
     _handleToggleAllInlineDiffs(e) {
       if (this.shouldSuppressKeyboardShortcut(e)) { return; }
 
       e.preventDefault();
       this._toggleInlineDiffs();
-    },
+    }
 
     _handleCursorNext(e) {
       if (this.shouldSuppressKeyboardShortcut(e) || this.modifierPressed(e)) {
@@ -616,7 +634,7 @@
         this.$.fileCursor.next();
         this.selectedIndex = this.$.fileCursor.index;
       }
-    },
+    }
 
     _handleCursorPrev(e) {
       if (this.shouldSuppressKeyboardShortcut(e) || this.modifierPressed(e)) {
@@ -634,14 +652,14 @@
         this.$.fileCursor.previous();
         this.selectedIndex = this.$.fileCursor.index;
       }
-    },
+    }
 
     _handleNewComment(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
           this.modifierPressed(e)) { return; }
       e.preventDefault();
       this.$.diffCursor.createCommentInPlace();
-    },
+    }
 
     _handleOpenLastFile(e) {
       // Check for meta key to avoid overriding native chrome shortcut.
@@ -650,7 +668,7 @@
 
       e.preventDefault();
       this._openSelectedFile(this._files.length - 1);
-    },
+    }
 
     _handleOpenFirstFile(e) {
       // Check for meta key to avoid overriding native chrome shortcut.
@@ -659,7 +677,7 @@
 
       e.preventDefault();
       this._openSelectedFile(0);
-    },
+    }
 
     _handleOpenFile(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
@@ -672,7 +690,7 @@
       }
 
       this._openSelectedFile();
-    },
+    }
 
     _handleNextChunk(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
@@ -687,7 +705,7 @@
       } else {
         this.$.diffCursor.moveToNextChunk();
       }
-    },
+    }
 
     _handlePrevChunk(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
@@ -702,7 +720,7 @@
       } else {
         this.$.diffCursor.moveToPreviousChunk();
       }
-    },
+    }
 
     _handleToggleFileReviewed(e) {
       if (this.shouldSuppressKeyboardShortcut(e) || this.modifierPressed(e)) {
@@ -712,7 +730,7 @@
       e.preventDefault();
       if (!this._files[this.$.fileCursor.index]) { return; }
       this._reviewFile(this._files[this.$.fileCursor.index].__path);
-    },
+    }
 
     _handleToggleLeftPane(e) {
       if (this.shouldSuppressKeyboardShortcut(e)) { return; }
@@ -721,7 +739,7 @@
       this._forEachDiff(diff => {
         diff.toggleLeftDiff();
       });
-    },
+    }
 
     _toggleInlineDiffs() {
       if (this._showInlineDiffs) {
@@ -729,13 +747,13 @@
       } else {
         this.expandAllDiffs();
       }
-    },
+    }
 
     _openCursorFile() {
       const diff = this.$.diffCursor.getTargetDiffElement();
       Gerrit.Nav.navigateToDiff(this.change, diff.path,
           diff.patchRange.patchNum, this.patchRange.basePatchNum);
-    },
+    }
 
     /**
      * @param {number=} opt_index
@@ -748,7 +766,7 @@
       Gerrit.Nav.navigateToDiff(this.change,
           this._files[this.$.fileCursor.index].__path, this.patchRange.patchNum,
           this.patchRange.basePatchNum);
-    },
+    }
 
     _addDraftAtTarget() {
       const diff = this.$.diffCursor.getTargetDiffElement();
@@ -756,20 +774,20 @@
       if (diff && target) {
         diff.addDraftAtLine(target);
       }
-    },
+    }
 
     _shouldHideChangeTotals(_patchChange) {
       return _patchChange.inserted === 0 && _patchChange.deleted === 0;
-    },
+    }
 
     _shouldHideBinaryChangeTotals(_patchChange) {
       return _patchChange.size_delta_inserted === 0 &&
           _patchChange.size_delta_deleted === 0;
-    },
+    }
 
     _computeFileStatus(status) {
       return status || 'M';
-    },
+    }
 
     _computeDiffURL(change, patchNum, basePatchNum, path, editMode) {
       // Polymer 2: check for undefined
@@ -784,7 +802,7 @@
             basePatchNum);
       }
       return Gerrit.Nav.getUrlForDiff(change, path, patchNum, basePatchNum);
-    },
+    }
 
     _formatBytes(bytes) {
       if (bytes == 0) return '+/-0 B';
@@ -796,7 +814,7 @@
       const prepend = bytes > 0 ? '+' : '';
       return prepend + parseFloat((bytes / Math.pow(bits, exponent))
           .toFixed(decimals)) + ' ' + sizes[exponent];
-    },
+    }
 
     _formatPercentage(size, delta) {
       const oldSize = size - delta;
@@ -805,12 +823,12 @@
 
       const percentage = Math.round(Math.abs(delta * 100 / oldSize));
       return '(' + (delta > 0 ? '+' : '-') + percentage + '%)';
-    },
+    }
 
     _computeBinaryClass(delta) {
       if (delta === 0) { return; }
       return delta >= 0 ? 'added' : 'removed';
-    },
+    }
 
     /**
      * @param {string} baseClass
@@ -825,16 +843,16 @@
         classes.push('invisible');
       }
       return classes.join(' ');
-    },
+    }
 
     _computePathClass(path, expandedFilesRecord) {
       return this._isFileExpanded(path, expandedFilesRecord) ? 'expanded' : '';
-    },
+    }
 
     _computeShowHideIcon(path, expandedFilesRecord) {
       return this._isFileExpanded(path, expandedFilesRecord) ?
         'gr-icons:expand-less' : 'gr-icons:expand-more';
-    },
+    }
 
     _computeFiles(filesByPath, changeComments, patchRange, reviewed, loading) {
       // Polymer 2: check for undefined
@@ -864,7 +882,7 @@
       }
 
       this._files = this._normalizeChangeFilesResponse(files);
-    },
+    }
 
     _computeFilesShown(numFilesShown, files) {
       // Polymer 2: check for undefined
@@ -888,13 +906,13 @@
           Math.max(0, filesShown.length - previousNumFilesShown);
 
       return filesShown;
-    },
+    }
 
     _updateDiffCursor() {
       // Overwrite the cursor's list of diffs:
       this.$.diffCursor.splice(
           ...['diffs', 0, this.$.diffCursor.diffs.length].concat(this.diffs));
-    },
+    }
 
     _filesChanged() {
       if (this._files && this._files.length > 0) {
@@ -904,41 +922,41 @@
         this.$.fileCursor.stops = files;
         this.$.fileCursor.setCursorAtIndex(this.selectedIndex, true);
       }
-    },
+    }
 
     _incrementNumFilesShown() {
       this.numFilesShown += this.fileListIncrement;
-    },
+    }
 
     _computeFileListControlClass(numFilesShown, files) {
       return numFilesShown >= files.length ? 'invisible' : '';
-    },
+    }
 
     _computeIncrementText(numFilesShown, files) {
       if (!files) { return ''; }
       const text =
           Math.min(this.fileListIncrement, files.length - numFilesShown);
       return 'Show ' + text + ' more';
-    },
+    }
 
     _computeShowAllText(files) {
       if (!files) { return ''; }
       return 'Show all ' + files.length + ' files';
-    },
+    }
 
     _computeWarnShowAll(files) {
       return files.length > WARN_SHOW_ALL_THRESHOLD;
-    },
+    }
 
     _computeShowAllWarning(files) {
       if (!this._computeWarnShowAll(files)) { return ''; }
       return 'Warning: showing all ' + files.length +
           ' files may take several seconds.';
-    },
+    }
 
     _showAllFiles() {
       this.numFilesShown = this._files.length;
-    },
+    }
 
     _computePatchSetDescription(revisions, patchNum) {
       // Polymer 2: check for undefined
@@ -949,7 +967,7 @@
       const rev = this.getRevisionByPatchNum(revisions, patchNum);
       return (rev && rev.description) ?
         rev.description.substring(0, PATCH_DESC_MAX_LENGTH) : '';
-    },
+    }
 
     /**
      * Get a descriptive label for use in the status indicator's tooltip and
@@ -961,16 +979,16 @@
       const statusCode = this._computeFileStatus(status);
       return FileStatus.hasOwnProperty(statusCode) ?
         FileStatus[statusCode] : 'Status Unknown';
-    },
+    }
 
     _isFileExpanded(path, expandedFilesRecord) {
       return expandedFilesRecord.base.includes(path);
-    },
+    }
 
     _onLineSelected(e, detail) {
       this.$.diffCursor.moveToLineNumber(detail.number, detail.side,
           detail.path);
-    },
+    }
 
     _computeExpandedFiles(expandedCount, totalCount) {
       if (expandedCount === 0) {
@@ -979,7 +997,7 @@
         return GrFileListConstants.FilesExpandedState.ALL;
       }
       return GrFileListConstants.FilesExpandedState.SOME;
-    },
+    }
 
     /**
      * Handle splices to the list of expanded file paths. If there are any new
@@ -1017,14 +1035,14 @@
 
       this._updateDiffCursor();
       this.$.diffCursor.handleDiffUpdate();
-    },
+    }
 
     _clearCollapsedDiffs(collapsedDiffs) {
       for (const diff of collapsedDiffs) {
         diff.cancel();
         diff.clearDiffContent();
       }
-    },
+    }
 
     /**
      * Given an array of paths and a NodeList of diff elements, render the diff
@@ -1065,13 +1083,13 @@
           this.$.diffCursor.handleDiffUpdate();
         });
       });
-    },
+    }
 
     /** Cancel the rendering work of every diff in the list */
     _cancelDiffs() {
       if (this._cancelForEachDiff) { this._cancelForEachDiff(); }
       this._forEachDiff(d => d.cancel());
-    },
+    }
 
     /**
      * In the given NodeList of diff elements, find the diff for the given path.
@@ -1085,7 +1103,7 @@
           return diffElements[i];
         }
       }
-    },
+    }
 
     /**
      * Reset the comments of a modified thread
@@ -1122,14 +1140,14 @@
       });
       Polymer.dom.flush();
       return;
-    },
+    }
 
     _handleEscKey(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
           this.modifierPressed(e)) { return; }
       e.preventDefault();
       this._displayLine = false;
-    },
+    }
 
     /**
      * Update the loading class for the file list rows. The update is inside a
@@ -1143,19 +1161,19 @@
         // this way, the gray loading style is not shown on initial loads.
         this.classList.toggle('loading', loading && !!this._files.length);
       }, LOADING_DEBOUNCE_INTERVAL);
-    },
+    }
 
     _editModeChanged(editMode) {
       this.classList.toggle('editMode', editMode);
-    },
+    }
 
     _computeReviewedClass(isReviewed) {
       return isReviewed ? 'isReviewed' : '';
-    },
+    }
 
     _computeReviewedText(isReviewed) {
       return isReviewed ? 'MARK UNREVIEWED' : 'MARK REVIEWED';
-    },
+    }
 
     /**
      * Given a file path, return whether that path should have visible size bars
@@ -1165,7 +1183,7 @@
      */
     _showBarsForPath(path) {
       return path !== this.COMMIT_MESSAGE_PATH && path !== this.MERGE_LIST_PATH;
-    },
+    }
 
     /**
      * Compute size bar layout values from the file list.
@@ -1199,7 +1217,7 @@
         stats.deletionOffset = stats.maxAdditionWidth + SIZE_BAR_GAP_WIDTH;
       }
       return stats;
-    },
+    }
 
     /**
      * Get the width of the addition bar for a file.
@@ -1216,7 +1234,7 @@
       const width =
           stats.maxAdditionWidth * file.lines_inserted / stats.maxInserted;
       return width === 0 ? 0 : Math.max(SIZE_BAR_MIN_WIDTH, width);
-    },
+    }
 
     /**
      * Get the x-offset of the addition bar for a file.
@@ -1227,7 +1245,7 @@
     _computeBarAdditionX(file, stats) {
       return stats.maxAdditionWidth -
           this._computeBarAdditionWidth(file, stats);
-    },
+    }
 
     /**
      * Get the width of the deletion bar for a file.
@@ -1244,7 +1262,7 @@
       const width =
           stats.maxDeletionWidth * file.lines_deleted / stats.maxDeleted;
       return width === 0 ? 0 : Math.max(SIZE_BAR_MIN_WIDTH, width);
-    },
+    }
 
     /**
      * Get the x-offset of the deletion bar for a file.
@@ -1253,11 +1271,11 @@
      */
     _computeBarDeletionX(stats) {
       return stats.deletionOffset;
-    },
+    }
 
     _computeShowSizeBars(userPrefs) {
       return !!userPrefs.size_bar_in_change_table;
-    },
+    }
 
     _computeSizeBarsClass(showSizeBars, path) {
       let hideClass = '';
@@ -1267,7 +1285,7 @@
         hideClass = 'invisible';
       }
       return `sizeBars desktop ${hideClass}`;
-    },
+    }
 
     /**
      * Shows registered dynamic columns iff the 'header', 'content' and
@@ -1280,7 +1298,7 @@
       return headerEndpoints && contentEndpoints && summaryEndpoints &&
              headerEndpoints.length === contentEndpoints.length &&
              headerEndpoints.length === summaryEndpoints.length;
-    },
+    }
 
     /**
      * Returns true if none of the inline diffs have been expanded.
@@ -1288,7 +1306,7 @@
      */
     _noDiffsExpanded() {
       return this.filesExpanded === GrFileListConstants.FilesExpandedState.NONE;
-    },
+    }
 
     /**
      * Method to call via binding when each file list row is rendered. This
@@ -1305,7 +1323,7 @@
         }, 1);
       }
       return '';
-    },
+    }
 
     _reviewedTitle(reviewed) {
       if (reviewed) {
@@ -1313,12 +1331,14 @@
       }
 
       return 'Mark as reviewed (shortcut: r)';
-    },
+    }
 
     _handleReloadingDiffPreference() {
       this._getDiffPreferences().then(prefs => {
         this.diffPrefs = prefs;
       });
-    },
-  });
+    }
+  }
+
+  customElements.define(GrFileList.is, GrFileList);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.js b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.js
index 4b8ce22..f0cba0b 100644
--- a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.js
@@ -17,36 +17,40 @@
 (function() {
   'use strict';
 
-  Polymer({
-    is: 'gr-included-in-dialog',
-
+  /**
+    * @appliesMixin Gerrit.FireMixin
+    */
+  class GrIncludedInDialog extends Polymer.mixinBehaviors( [
+    Gerrit.FireBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-included-in-dialog'; }
     /**
      * Fired when the user presses the close button.
      *
      * @event close
      */
 
-    properties: {
+    static get properties() {
+      return {
       /** @type {?} */
-      changeNum: {
-        type: Object,
-        observer: '_resetData',
-      },
-      /** @type {?} */
-      _includedIn: Object,
-      _loaded: {
-        type: Boolean,
-        value: false,
-      },
-      _filterText: {
-        type: String,
-        value: '',
-      },
-    },
-
-    behaviors: [
-      Gerrit.FireBehavior,
-    ],
+        changeNum: {
+          type: Object,
+          observer: '_resetData',
+        },
+        /** @type {?} */
+        _includedIn: Object,
+        _loaded: {
+          type: Boolean,
+          value: false,
+        },
+        _filterText: {
+          type: String,
+          value: '',
+        },
+      };
+    }
 
     loadData() {
       if (!this.changeNum) { return; }
@@ -57,12 +61,12 @@
             this._includedIn = configs;
             this._loaded = true;
           });
-    },
+    }
 
     _resetData() {
       this._includedIn = null;
       this._loaded = false;
-    },
+    }
 
     _computeGroups(includedIn, filterText) {
       if (!includedIn) { return []; }
@@ -83,22 +87,24 @@
         }
       }
       return groups.filter(g => g.items.length);
-    },
+    }
 
     _handleCloseTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.fire('close', null, {bubbles: false});
-    },
+    }
 
     _computeLoadingClass(loaded) {
       return loaded ? 'loading loaded' : 'loading';
-    },
+    }
 
     _onFilterChanged() {
       this.debounce('filter-change', () => {
         this._filterText = this.$.filterInput.bindValue;
       }, 100);
-    },
-  });
+    }
+  }
+
+  customElements.define(GrIncludedInDialog.is, GrIncludedInDialog);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js
index bd7fff8..abfe469 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js
@@ -17,56 +17,59 @@
 (function() {
   'use strict';
 
-  Polymer({
-    is: 'gr-label-score-row',
-
+  class GrLabelScoreRow extends Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element)) {
+    static get is() { return 'gr-label-score-row'; }
     /**
      * Fired when any label is changed.
      *
      * @event labels-changed
      */
 
-    properties: {
+    static get properties() {
+      return {
       /**
        * @type {{ name: string }}
        */
-      label: Object,
-      labels: Object,
-      name: {
-        type: String,
-        reflectToAttribute: true,
-      },
-      permittedLabels: Object,
-      labelValues: Object,
-      _selectedValueText: {
-        type: String,
-        value: 'No value selected',
-      },
-      _items: {
-        type: Array,
-        computed: '_computePermittedLabelValues(permittedLabels, label.name)',
-      },
-    },
+        label: Object,
+        labels: Object,
+        name: {
+          type: String,
+          reflectToAttribute: true,
+        },
+        permittedLabels: Object,
+        labelValues: Object,
+        _selectedValueText: {
+          type: String,
+          value: 'No value selected',
+        },
+        _items: {
+          type: Array,
+          computed: '_computePermittedLabelValues(permittedLabels, label.name)',
+        },
+      };
+    }
 
     get selectedItem() {
       if (!this._ironSelector) { return undefined; }
       return this._ironSelector.selectedItem;
-    },
+    }
 
     get selectedValue() {
       if (!this._ironSelector) { return undefined; }
       return this._ironSelector.selected;
-    },
+    }
 
     setSelectedValue(value) {
       // The selector may not be present if it’s not at the latest patch set.
       if (!this._ironSelector) { return; }
       this._ironSelector.select(value);
-    },
+    }
 
     get _ironSelector() {
       return this.$ && this.$.labelSelector;
-    },
+    }
 
     _computeBlankItems(permittedLabels, label, side) {
       if (!permittedLabels || !permittedLabels[label] ||
@@ -82,7 +85,7 @@
       const endPosition = this.labelValues[parseInt(
           permittedLabels[label][permittedLabels[label].length - 1], 10)];
       return new Array(Object.keys(this.labelValues).length - endPosition - 1);
-    },
+    }
 
     _getLabelValue(labels, permittedLabels, label) {
       if (label.value) {
@@ -93,7 +96,7 @@
         return permittedLabels[label.name].find(
             value => parseInt(value, 10) === labels[label.name].default_value);
       }
-    },
+    }
 
     _computeButtonClass(value, index, totalItems) {
       const classes = [];
@@ -114,7 +117,7 @@
       }
 
       return classes.join(' ');
-    },
+    }
 
     _computeLabelValue(labels, permittedLabels, label) {
       if ([labels, permittedLabels, label].some(arg => arg === undefined)) {
@@ -131,7 +134,7 @@
         }
       }
       return null;
-    },
+    }
 
     _setSelectedValueText(e) {
       // Needed because when the selected item changes, it first changes to
@@ -145,17 +148,17 @@
       this.dispatchEvent(new CustomEvent(
           'labels-changed',
           {detail: {name, value}, bubbles: true, composed: true}));
-    },
+    }
 
     _computeAnyPermittedLabelValues(permittedLabels, label) {
       return permittedLabels && permittedLabels.hasOwnProperty(label) &&
         permittedLabels[label].length;
-    },
+    }
 
     _computeHiddenClass(permittedLabels, label) {
       return !this._computeAnyPermittedLabelValues(permittedLabels, label) ?
         'hidden' : '';
-    },
+    }
 
     _computePermittedLabelValues(permittedLabels, label) {
       // Polymer 2: check for undefined
@@ -164,12 +167,14 @@
       }
 
       return permittedLabels[label];
-    },
+    }
 
     _computeLabelValueTitle(labels, label, value) {
       return labels[label] &&
         labels[label].values &&
         labels[label].values[value];
-    },
-  });
+    }
+  }
+
+  customElements.define(GrLabelScoreRow.is, GrLabelScoreRow);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.js b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.js
index 9424907..2c164f1 100644
--- a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.js
+++ b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.js
@@ -17,25 +17,29 @@
 (function() {
   'use strict';
 
-  Polymer({
-    is: 'gr-label-scores',
+  class GrLabelScores extends Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element)) {
+    static get is() { return 'gr-label-scores'; }
 
-    properties: {
-      _labels: {
-        type: Array,
-        computed: '_computeLabels(change.labels.*, account)',
-      },
-      permittedLabels: {
-        type: Object,
-        observer: '_computeColumns',
-      },
-      /** @type {?} */
-      change: Object,
-      /** @type {?} */
-      account: Object,
+    static get properties() {
+      return {
+        _labels: {
+          type: Array,
+          computed: '_computeLabels(change.labels.*, account)',
+        },
+        permittedLabels: {
+          type: Object,
+          observer: '_computeColumns',
+        },
+        /** @type {?} */
+        change: Object,
+        /** @type {?} */
+        account: Object,
 
-      _labelValues: Object,
-    },
+        _labelValues: Object,
+      };
+    }
 
     getLabelValues() {
       const labels = {};
@@ -61,7 +65,7 @@
         }
       }
       return labels;
-    },
+    }
 
     _getStringLabelValue(labels, labelName, numberValue) {
       for (const k in labels[labelName].values) {
@@ -70,7 +74,7 @@
         }
       }
       return numberValue;
-    },
+    }
 
     _getVoteForAccount(labels, labelName, account) {
       const votes = labels[labelName];
@@ -83,7 +87,7 @@
         }
       }
       return null;
-    },
+    }
 
     _computeLabels(labelRecord, account) {
       // Polymer 2: check for undefined
@@ -99,7 +103,7 @@
           value: this._getVoteForAccount(labelsObj, key, this.account),
         };
       });
-    },
+    }
 
     _computeColumns(permittedLabels) {
       const labels = Object.keys(permittedLabels);
@@ -118,11 +122,11 @@
         values[orderedValues[i]] = i;
       }
       this._labelValues = values;
-    },
+    }
 
     _changeIsMerged(changeStatus) {
       return changeStatus === 'MERGED';
-    },
+    }
 
     /**
      * @param label {string|undefined}
@@ -136,6 +140,8 @@
 
       return permittedLabels.hasOwnProperty(label) &&
         permittedLabels[label].length ? 'access' : 'no-access';
-    },
-  });
+    }
+  }
+
+  customElements.define(GrLabelScores.is, GrLabelScores);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message.js b/polygerrit-ui/app/elements/change/gr-message/gr-message.js
index 26e0cd3..7c1d66c 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message.js
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message.js
@@ -20,9 +20,15 @@
   const PATCH_SET_PREFIX_PATTERN = /^Patch Set \d+: /;
   const LABEL_TITLE_SCORE_PATTERN = /^([A-Za-z0-9-]+)([+-]\d+)$/;
 
-  Polymer({
-    is: 'gr-message',
-
+  /**
+    * @appliesMixin Gerrit.FireMixin
+    */
+  class GrMessage extends Polymer.mixinBehaviors( [
+    Gerrit.FireBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-message'; }
     /**
      * Fired when this message's reply link is tapped.
      *
@@ -35,90 +41,93 @@
      * @event message-anchor-tap
      */
 
-    listeners: {
-      click: '_handleClick',
-    },
+    static get properties() {
+      return {
+        changeNum: Number,
+        /** @type {?} */
+        message: Object,
+        author: {
+          type: Object,
+          computed: '_computeAuthor(message)',
+        },
+        comments: {
+          type: Object,
+          observer: '_commentsChanged',
+        },
+        config: Object,
+        hideAutomated: {
+          type: Boolean,
+          value: false,
+        },
+        hidden: {
+          type: Boolean,
+          computed: '_computeIsHidden(hideAutomated, isAutomated)',
+          reflectToAttribute: true,
+        },
+        isAutomated: {
+          type: Boolean,
+          computed: '_computeIsAutomated(message)',
+        },
+        showAvatar: {
+          type: Boolean,
+          computed: '_computeShowAvatar(author, config)',
+        },
+        showOnBehalfOf: {
+          type: Boolean,
+          computed: '_computeShowOnBehalfOf(message)',
+        },
+        showReplyButton: {
+          type: Boolean,
+          computed: '_computeShowReplyButton(message, _loggedIn)',
+        },
+        projectName: {
+          type: String,
+          observer: '_projectNameChanged',
+        },
 
-    properties: {
-      changeNum: Number,
-      /** @type {?} */
-      message: Object,
-      author: {
-        type: Object,
-        computed: '_computeAuthor(message)',
-      },
-      comments: {
-        type: Object,
-        observer: '_commentsChanged',
-      },
-      config: Object,
-      hideAutomated: {
-        type: Boolean,
-        value: false,
-      },
-      hidden: {
-        type: Boolean,
-        computed: '_computeIsHidden(hideAutomated, isAutomated)',
-        reflectToAttribute: true,
-      },
-      isAutomated: {
-        type: Boolean,
-        computed: '_computeIsAutomated(message)',
-      },
-      showAvatar: {
-        type: Boolean,
-        computed: '_computeShowAvatar(author, config)',
-      },
-      showOnBehalfOf: {
-        type: Boolean,
-        computed: '_computeShowOnBehalfOf(message)',
-      },
-      showReplyButton: {
-        type: Boolean,
-        computed: '_computeShowReplyButton(message, _loggedIn)',
-      },
-      projectName: {
-        type: String,
-        observer: '_projectNameChanged',
-      },
-
-      /**
+        /**
        * A mapping from label names to objects representing the minimum and
        * maximum possible values for that label.
        */
-      labelExtremes: Object,
+        labelExtremes: Object,
 
-      /**
+        /**
        * @type {{ commentlinks: Array }}
        */
-      _projectConfig: Object,
-      // Computed property needed to trigger Polymer value observing.
-      _expanded: {
-        type: Object,
-        computed: '_computeExpanded(message.expanded)',
-      },
-      _loggedIn: {
-        type: Boolean,
-        value: false,
-      },
-    },
+        _projectConfig: Object,
+        // Computed property needed to trigger Polymer value observing.
+        _expanded: {
+          type: Object,
+          computed: '_computeExpanded(message.expanded)',
+        },
+        _loggedIn: {
+          type: Boolean,
+          value: false,
+        },
+      };
+    }
 
-    behaviors: [
-      Gerrit.FireBehavior,
-    ],
+    static get observers() {
+      return [
+        '_updateExpandedClass(message.expanded)',
+      ];
+    }
 
-    observers: [
-      '_updateExpandedClass(message.expanded)',
-    ],
+    created() {
+      super.created();
+      this.addEventListener('click',
+          e => this._handleClick(e));
+    }
 
     ready() {
+      super.ready();
       this.$.restAPI.getConfig().then(config => {
         this.config = config;
       });
       this.$.restAPI.getLoggedIn().then(loggedIn => {
         this._loggedIn = loggedIn;
       });
-    },
+    }
 
     _updateExpandedClass(expanded) {
       if (expanded) {
@@ -126,30 +135,30 @@
       } else {
         this.classList.remove('expanded');
       }
-    },
+    }
 
     _computeAuthor(message) {
       return message.author || message.updated_by;
-    },
+    }
 
     _computeShowAvatar(author, config) {
       return !!(author && config && config.plugin && config.plugin.has_avatars);
-    },
+    }
 
     _computeShowOnBehalfOf(message) {
       const author = message.author || message.updated_by;
       return !!(author && message.real_author &&
           author._account_id != message.real_author._account_id);
-    },
+    }
 
     _computeShowReplyButton(message, loggedIn) {
       return message && !!message.message && loggedIn &&
           !this._computeIsAutomated(message);
-    },
+    }
 
     _computeExpanded(expanded) {
       return expanded;
-    },
+    }
 
     /**
      * If there is no value set on the message object as to whether _expanded
@@ -160,33 +169,33 @@
       if (this.message && this.message.expanded === undefined) {
         this.set('message.expanded', Object.keys(value || {}).length > 0);
       }
-    },
+    }
 
     _handleClick(e) {
       if (this.message.expanded) { return; }
       e.stopPropagation();
       this.set('message.expanded', true);
-    },
+    }
 
     _handleAuthorClick(e) {
       if (!this.message.expanded) { return; }
       e.stopPropagation();
       this.set('message.expanded', false);
-    },
+    }
 
     _computeIsAutomated(message) {
       return !!(message.reviewer ||
           this._computeIsReviewerUpdate(message) ||
           (message.tag && message.tag.startsWith('autogenerated')));
-    },
+    }
 
     _computeIsHidden(hideAutomated, isAutomated) {
       return hideAutomated && isAutomated;
-    },
+    }
 
     _computeIsReviewerUpdate(event) {
       return event.type === 'REVIEWER_UPDATE';
-    },
+    }
 
     _getScores(message) {
       if (!message.message) { return []; }
@@ -199,7 +208,7 @@
           .map(s => s.match(LABEL_TITLE_SCORE_PATTERN))
           .filter(ms => ms && ms.length === 3)
           .map(ms => ({label: ms[1], value: ms[2]}));
-    },
+    }
 
     _computeScoreClass(score, labelExtremes) {
       // Polymer 2: check for undefined
@@ -222,14 +231,14 @@
         }
       }
       return classes.join(' ');
-    },
+    }
 
     _computeClass(expanded, showAvatar, message) {
       const classes = [];
       classes.push(expanded ? 'expanded' : 'collapsed');
       classes.push(showAvatar ? 'showAvatar' : 'hideAvatar');
       return classes.join(' ');
-    },
+    }
 
     _handleAnchorClick(e) {
       e.preventDefault();
@@ -238,26 +247,28 @@
         composed: true,
         detail: {id: this.message.id},
       }));
-    },
+    }
 
     _handleReplyTap(e) {
       e.preventDefault();
       this.fire('reply', {message: this.message});
-    },
+    }
 
     _projectNameChanged(name) {
       this.$.restAPI.getProjectConfig(name).then(config => {
         this._projectConfig = config;
       });
-    },
+    }
 
     _computeExpandToggleIcon(expanded) {
       return expanded ? 'gr-icons:expand-less' : 'gr-icons:expand-more';
-    },
+    }
 
     _toggleExpanded(e) {
       e.stopPropagation();
       this.set('message.expanded', !this.message.expanded);
-    },
-  });
+    }
+  }
+
+  customElements.define(GrMessage.is, GrMessage);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.js b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.js
index d90132d..92e7cce 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.js
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.js
@@ -25,57 +25,61 @@
     SHOW_MORE: 'show-more-messages',
   };
 
-  Polymer({
-    is: 'gr-messages-list',
+  class GrMessagesList extends Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element)) {
+    static get is() { return 'gr-messages-list'; }
 
-    properties: {
-      changeNum: Number,
-      messages: {
-        type: Array,
-        value() { return []; },
-      },
-      reviewerUpdates: {
-        type: Array,
-        value() { return []; },
-      },
-      changeComments: Object,
-      projectName: String,
-      showReplyButtons: {
-        type: Boolean,
-        value: false,
-      },
-      labels: Object,
+    static get properties() {
+      return {
+        changeNum: Number,
+        messages: {
+          type: Array,
+          value() { return []; },
+        },
+        reviewerUpdates: {
+          type: Array,
+          value() { return []; },
+        },
+        changeComments: Object,
+        projectName: String,
+        showReplyButtons: {
+          type: Boolean,
+          value: false,
+        },
+        labels: Object,
 
-      _expanded: {
-        type: Boolean,
-        value: false,
-        observer: '_expandedChanged',
-      },
-      _hideAutomated: {
-        type: Boolean,
-        value: false,
-      },
-      /**
+        _expanded: {
+          type: Boolean,
+          value: false,
+          observer: '_expandedChanged',
+        },
+        _hideAutomated: {
+          type: Boolean,
+          value: false,
+        },
+        /**
        * The messages after processing and including merged reviewer updates.
        */
-      _processedMessages: {
-        type: Array,
-        computed: '_computeItems(messages, reviewerUpdates)',
-        observer: '_processedMessagesChanged',
-      },
-      /**
+        _processedMessages: {
+          type: Array,
+          computed: '_computeItems(messages, reviewerUpdates)',
+          observer: '_processedMessagesChanged',
+        },
+        /**
        * The subset of _processedMessages that is visible to the user.
        */
-      _visibleMessages: {
-        type: Array,
-        value() { return []; },
-      },
+        _visibleMessages: {
+          type: Array,
+          value() { return []; },
+        },
 
-      _labelExtremes: {
-        type: Object,
-        computed: '_computeLabelExtremes(labels.*)',
-      },
-    },
+        _labelExtremes: {
+          type: Object,
+          computed: '_computeLabelExtremes(labels.*)',
+        },
+      };
+    }
 
     scrollToMessage(messageID) {
       let el = this.$$('[data-message-id="' + messageID + '"]');
@@ -108,12 +112,12 @@
       }
       window.scrollTo(0, top);
       this._highlightEl(el);
-    },
+    }
 
     _isAutomated(message) {
       return !!(message.reviewer ||
           (message.tag && message.tag.startsWith('autogenerated')));
-    },
+    }
 
     _computeItems(messages, reviewerUpdates) {
       // Polymer 2: check for undefined
@@ -152,7 +156,7 @@
         }
       }
       return result;
-    },
+    }
 
     _expandedChanged(exp) {
       if (this._processedMessages) {
@@ -169,7 +173,7 @@
           this.notifyPath(`_visibleMessages.${i}.expanded`);
         }
       }
-    },
+    }
 
     _highlightEl(el) {
       const highlightedEls =
@@ -183,23 +187,23 @@
       }
       el.addEventListener('animationend', handleAnimationEnd);
       el.classList.add('highlighted');
-    },
+    }
 
     /**
      * @param {boolean} expand
      */
     handleExpandCollapse(expand) {
       this._expanded = expand;
-    },
+    }
 
     _handleExpandCollapseTap(e) {
       e.preventDefault();
       this.handleExpandCollapse(!this._expanded);
-    },
+    }
 
     _handleAnchorClick(e) {
       this.scrollToMessage(e.detail.id);
-    },
+    }
 
     _hasAutomatedMessages(messages) {
       if (!messages) { return false; }
@@ -209,11 +213,11 @@
         }
       }
       return false;
-    },
+    }
 
     _computeExpandCollapseMessage(expanded) {
       return expanded ? 'Collapse all' : 'Expand all';
-    },
+    }
 
     /**
      * Computes message author's file comments for change's message.
@@ -268,7 +272,7 @@
         }
       }
       return msgComments;
-    },
+    }
 
     /**
      * Returns the number of messages to splice to the beginning of
@@ -293,7 +297,7 @@
         delta = msgsRemaining - i;
       }
       return Math.min(msgsRemaining, delta);
-    },
+    }
 
     /**
      * Gets the number of messages that would be visible, but do not currently
@@ -309,20 +313,20 @@
             this._getHumanMessages(visibleMessages).length;
       }
       return messages.length - visibleMessages.length;
-    },
+    }
 
     _computeIncrementText(visibleMessages, messages, hideAutomated) {
       let delta = this._getDelta(visibleMessages, messages, hideAutomated);
       delta = Math.min(
           this._numRemaining(visibleMessages, messages, hideAutomated), delta);
       return 'Show ' + Math.min(MESSAGES_INCREMENT, delta) + ' more';
-    },
+    }
 
     _getHumanMessages(messages) {
       return messages.filter(msg => {
         return !this._isAutomated(msg);
       });
-    },
+    }
 
     _computeShowHideTextHidden(visibleMessages, messages,
         hideAutomated) {
@@ -335,12 +339,12 @@
         visibleMessages = this._getHumanMessages(visibleMessages);
       }
       return visibleMessages.length >= messages.length;
-    },
+    }
 
     _handleShowAllTap() {
       this._visibleMessages = this._processedMessages;
       this.$.reporting.reportInteraction(ReportingEvent.SHOW_ALL);
-    },
+    }
 
     _handleIncrementShownMessages() {
       const delta = this._getDelta(this._visibleMessages,
@@ -350,27 +354,27 @@
       // Add newMessages to the beginning of _visibleMessages
       this.splice(...['_visibleMessages', 0, 0].concat(newMessages));
       this.$.reporting.reportInteraction(ReportingEvent.SHOW_MORE);
-    },
+    }
 
     _processedMessagesChanged(messages) {
       if (messages) {
         this._visibleMessages = messages.slice(-MAX_INITIAL_SHOWN_MESSAGES);
       }
-    },
+    }
 
     _computeNumMessagesText(visibleMessages, messages,
         hideAutomated) {
       const total =
           this._numRemaining(visibleMessages, messages, hideAutomated);
       return total === 1 ? 'Show 1 message' : 'Show all ' + total + ' messages';
-    },
+    }
 
     _computeIncrementHidden(visibleMessages, messages,
         hideAutomated) {
       const total =
           this._numRemaining(visibleMessages, messages, hideAutomated);
       return total <= this._getDelta(visibleMessages, messages, hideAutomated);
-    },
+    }
 
     /**
      * Compute a mapping from label name to objects representing the minimum and
@@ -389,6 +393,8 @@
         extremes[key] = {min: values[0], max: values[values.length - 1]};
       }
       return extremes;
-    },
-  });
+    }
+  }
+
+  customElements.define(GrMessagesList.is, GrMessagesList);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
index 18a136e..25a56a9 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
@@ -17,9 +17,19 @@
 (function() {
   'use strict';
 
-  Polymer({
-    is: 'gr-related-changes-list',
-
+  /**
+    * @appliesMixin Gerrit.FireMixin
+    * @appliesMixin Gerrit.PatchSetMixin
+    * @appliesMixin Gerrit.RESTClientMixin
+    */
+  class GrRelatedChangesList extends Polymer.mixinBehaviors( [
+    Gerrit.FireBehavior,
+    Gerrit.PatchSetBehavior,
+    Gerrit.RESTClientBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-related-changes-list'; }
     /**
      * Fired when a new section is loaded so that the change view can determine
      * a show more button is needed, sometimes before all the sections finish
@@ -28,64 +38,62 @@
      * @event new-section-loaded
      */
 
-    properties: {
-      change: Object,
-      hasParent: {
-        type: Boolean,
-        notify: true,
-        value: false,
-      },
-      patchNum: String,
-      parentChange: Object,
-      hidden: {
-        type: Boolean,
-        value: false,
-        reflectToAttribute: true,
-      },
-      loading: {
-        type: Boolean,
-        notify: true,
-      },
-      mergeable: Boolean,
-      _connectedRevisions: {
-        type: Array,
-        computed: '_computeConnectedRevisions(change, patchNum, ' +
+    static get properties() {
+      return {
+        change: Object,
+        hasParent: {
+          type: Boolean,
+          notify: true,
+          value: false,
+        },
+        patchNum: String,
+        parentChange: Object,
+        hidden: {
+          type: Boolean,
+          value: false,
+          reflectToAttribute: true,
+        },
+        loading: {
+          type: Boolean,
+          notify: true,
+        },
+        mergeable: Boolean,
+        _connectedRevisions: {
+          type: Array,
+          computed: '_computeConnectedRevisions(change, patchNum, ' +
             '_relatedResponse.changes)',
-      },
-      /** @type {?} */
-      _relatedResponse: {
-        type: Object,
-        value() { return {changes: []}; },
-      },
-      /** @type {?} */
-      _submittedTogether: {
-        type: Object,
-        value() { return {changes: []}; },
-      },
-      _conflicts: {
-        type: Array,
-        value() { return []; },
-      },
-      _cherryPicks: {
-        type: Array,
-        value() { return []; },
-      },
-      _sameTopic: {
-        type: Array,
-        value() { return []; },
-      },
-    },
+        },
+        /** @type {?} */
+        _relatedResponse: {
+          type: Object,
+          value() { return {changes: []}; },
+        },
+        /** @type {?} */
+        _submittedTogether: {
+          type: Object,
+          value() { return {changes: []}; },
+        },
+        _conflicts: {
+          type: Array,
+          value() { return []; },
+        },
+        _cherryPicks: {
+          type: Array,
+          value() { return []; },
+        },
+        _sameTopic: {
+          type: Array,
+          value() { return []; },
+        },
+      };
+    }
 
-    behaviors: [
-      Gerrit.FireBehavior,
-      Gerrit.PatchSetBehavior,
-      Gerrit.RESTClientBehavior,
-    ],
-
-    observers: [
-      '_resultsChanged(_relatedResponse, _submittedTogether, ' +
+    static get observers() {
+      return [
+        '_resultsChanged(_relatedResponse, _submittedTogether, ' +
           '_conflicts, _cherryPicks, _sameTopic)',
-    ],
+      ];
+    }
 
     clear() {
       this.loading = true;
@@ -96,7 +104,7 @@
       this._conflicts = [];
       this._cherryPicks = [];
       this._sameTopic = [];
-    },
+    }
 
     reload() {
       if (!this.change || !this.patchNum) {
@@ -144,7 +152,7 @@
       return Promise.all(promises).then(() => {
         this.loading = false;
       });
-    },
+    }
 
     _fireReloadEvent() {
       // The listener on the change computes height of the related changes
@@ -152,7 +160,7 @@
       // that requires a flush.
       Polymer.dom.flush();
       this.dispatchEvent(new CustomEvent('new-section-loaded'));
-    },
+    }
 
     /**
      * Determines whether or not the given change has a parent change. If there
@@ -166,34 +174,34 @@
       return relatedChanges.length > 0 &&
           relatedChanges[relatedChanges.length - 1].change_id !==
           currentChangeId;
-    },
+    }
 
     _getRelatedChanges() {
       return this.$.restAPI.getRelatedChanges(this.change._number,
           this.patchNum);
-    },
+    }
 
     _getSubmittedTogether() {
       return this.$.restAPI.getChangesSubmittedTogether(this.change._number);
-    },
+    }
 
     _getServerConfig() {
       return this.$.restAPI.getConfig();
-    },
+    }
 
     _getConflicts() {
       return this.$.restAPI.getChangeConflicts(this.change._number);
-    },
+    }
 
     _getCherryPicks() {
       return this.$.restAPI.getChangeCherryPicks(this.change.project,
           this.change.change_id, this.change._number);
-    },
+    }
 
     _getChangesWithSameTopic() {
       return this.$.restAPI.getChangesWithSameTopic(this.change.topic,
           this.change._number);
-    },
+    }
 
     /**
      * @param {number} changeNum
@@ -203,7 +211,7 @@
      */
     _computeChangeURL(changeNum, project, opt_patchNum) {
       return Gerrit.Nav.getUrlForChangeById(changeNum, project, opt_patchNum);
-    },
+    }
 
     _computeChangeContainerClass(currentChange, relatedChange) {
       const classes = ['changeContainer'];
@@ -214,7 +222,7 @@
         classes.push('thisChange');
       }
       return classes.join(' ');
-    },
+    }
 
     /**
      * Do the given objects describe the same change? Compares the changes by
@@ -229,7 +237,7 @@
       const aNum = this._getChangeNumber(a);
       const bNum = this._getChangeNumber(b);
       return aNum === bNum;
-    },
+    }
 
     /**
      * Get the change number from either a ChangeInfo (such as those included in
@@ -251,7 +259,7 @@
         return change._change_number;
       }
       return change._number;
-    },
+    }
 
     _computeLinkClass(change) {
       const statuses = [];
@@ -262,7 +270,7 @@
         statuses.push('submittable');
       }
       return statuses.join(' ');
-    },
+    }
 
     _computeChangeStatusClass(change) {
       const classes = ['status'];
@@ -276,7 +284,7 @@
         classes.push('hidden');
       }
       return classes.join(' ');
-    },
+    }
 
     _computeChangeStatus(change) {
       switch (change.status) {
@@ -293,7 +301,7 @@
         return 'Submittable';
       }
       return '';
-    },
+    }
 
     _resultsChanged(related, submittedTogether, conflicts,
         cherryPicks, sameTopic) {
@@ -323,11 +331,11 @@
         }
       }
       this.hidden = true;
-    },
+    }
 
     _isIndirectAncestor(change) {
       return !this._connectedRevisions.includes(change.commit.commit);
-    },
+    }
 
     _computeConnectedRevisions(change, patchNum, relatedChanges) {
       // Polymer 2: check for undefined
@@ -364,7 +372,7 @@
         --pos;
       }
       return connected;
-    },
+    }
 
     _computeSubmittedTogetherClass(submittedTogether) {
       if (!submittedTogether || (
@@ -373,11 +381,13 @@
         return 'hidden';
       }
       return '';
-    },
+    }
 
     _computeNonVisibleChangesNote(n) {
       const noun = n === 1 ? 'change' : 'changes';
       return `(+ ${n} non-visible ${noun})`;
-    },
-  });
+    }
+  }
+
+  customElements.define(GrRelatedChangesList.is, GrRelatedChangesList);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
index 3c5da92..eab1c8d 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
@@ -52,9 +52,23 @@
 
   const SEND_REPLY_TIMING_LABEL = 'SendReply';
 
-  Polymer({
-    is: 'gr-reply-dialog',
-
+  /**
+    * @appliesMixin Gerrit.BaseUrlMixin
+    * @appliesMixin Gerrit.FireMixin
+    * @appliesMixin Gerrit.KeyboardShortcutMixin
+    * @appliesMixin Gerrit.PatchSetMixin
+    * @appliesMixin Gerrit.RESTClientMixin
+    */
+  class GrReplyDialog extends Polymer.mixinBehaviors( [
+    Gerrit.BaseUrlBehavior,
+    Gerrit.FireBehavior,
+    Gerrit.KeyboardShortcutBehavior,
+    Gerrit.PatchSetBehavior,
+    Gerrit.RESTClientBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-reply-dialog'; }
     /**
      * Fired when a reply is successfully sent.
      *
@@ -93,156 +107,159 @@
       * @event send-disabled-changed
       */
 
-    properties: {
+    constructor() {
+      super();
+      this.FocusTarget = FocusTarget;
+    }
+
+    static get properties() {
+      return {
       /**
        * @type {{ _number: number, removable_reviewers: Array }}
        */
-      change: Object,
-      patchNum: String,
-      canBeStarted: {
-        type: Boolean,
-        value: false,
-      },
-      disabled: {
-        type: Boolean,
-        value: false,
-        reflectToAttribute: true,
-      },
-      draft: {
-        type: String,
-        value: '',
-        observer: '_draftChanged',
-      },
-      quote: {
-        type: String,
-        value: '',
-      },
-      diffDrafts: {
-        type: Object,
-        observer: '_handleHeightChanged',
-      },
-      /** @type {!Function} */
-      filterReviewerSuggestion: {
-        type: Function,
-        value() {
-          return this._filterReviewerSuggestionGenerator(false);
+        change: Object,
+        patchNum: String,
+        canBeStarted: {
+          type: Boolean,
+          value: false,
         },
-      },
-      /** @type {!Function} */
-      filterCCSuggestion: {
-        type: Function,
-        value() {
-          return this._filterReviewerSuggestionGenerator(true);
+        disabled: {
+          type: Boolean,
+          value: false,
+          reflectToAttribute: true,
         },
-      },
-      permittedLabels: Object,
-      /**
+        draft: {
+          type: String,
+          value: '',
+          observer: '_draftChanged',
+        },
+        quote: {
+          type: String,
+          value: '',
+        },
+        diffDrafts: {
+          type: Object,
+          observer: '_handleHeightChanged',
+        },
+        /** @type {!Function} */
+        filterReviewerSuggestion: {
+          type: Function,
+          value() {
+            return this._filterReviewerSuggestionGenerator(false);
+          },
+        },
+        /** @type {!Function} */
+        filterCCSuggestion: {
+          type: Function,
+          value() {
+            return this._filterReviewerSuggestionGenerator(true);
+          },
+        },
+        permittedLabels: Object,
+        /**
        * @type {{ commentlinks: Array }}
        */
-      projectConfig: Object,
-      knownLatestState: String,
-      underReview: {
-        type: Boolean,
-        value: true,
-      },
-
-      _account: Object,
-      _ccs: Array,
-      /** @type {?Object} */
-      _ccPendingConfirmation: {
-        type: Object,
-        observer: '_reviewerPendingConfirmationUpdated',
-      },
-      _messagePlaceholder: {
-        type: String,
-        computed: '_computeMessagePlaceholder(canBeStarted)',
-      },
-      _owner: Object,
-      /** @type {?} */
-      _pendingConfirmationDetails: Object,
-      _includeComments: {
-        type: Boolean,
-        value: true,
-      },
-      _reviewers: Array,
-      /** @type {?Object} */
-      _reviewerPendingConfirmation: {
-        type: Object,
-        observer: '_reviewerPendingConfirmationUpdated',
-      },
-      _previewFormatting: {
-        type: Boolean,
-        value: false,
-        observer: '_handleHeightChanged',
-      },
-      _reviewersPendingRemove: {
-        type: Object,
-        value: {
-          CC: [],
-          REVIEWER: [],
+        projectConfig: Object,
+        knownLatestState: String,
+        underReview: {
+          type: Boolean,
+          value: true,
         },
-      },
-      _sendButtonLabel: {
-        type: String,
-        computed: '_computeSendButtonLabel(canBeStarted)',
-      },
-      _savingComments: Boolean,
-      _reviewersMutated: {
-        type: Boolean,
-        value: false,
-      },
-      _labelsChanged: {
-        type: Boolean,
-        value: false,
-      },
-      _saveTooltip: {
-        type: String,
-        value: ButtonTooltips.SAVE,
-        readOnly: true,
-      },
-      _pluginMessage: {
-        type: String,
-        value: '',
-      },
-      _sendDisabled: {
-        type: Boolean,
-        computed: '_computeSendButtonDisabled(_sendButtonLabel, ' +
+
+        _account: Object,
+        _ccs: Array,
+        /** @type {?Object} */
+        _ccPendingConfirmation: {
+          type: Object,
+          observer: '_reviewerPendingConfirmationUpdated',
+        },
+        _messagePlaceholder: {
+          type: String,
+          computed: '_computeMessagePlaceholder(canBeStarted)',
+        },
+        _owner: Object,
+        /** @type {?} */
+        _pendingConfirmationDetails: Object,
+        _includeComments: {
+          type: Boolean,
+          value: true,
+        },
+        _reviewers: Array,
+        /** @type {?Object} */
+        _reviewerPendingConfirmation: {
+          type: Object,
+          observer: '_reviewerPendingConfirmationUpdated',
+        },
+        _previewFormatting: {
+          type: Boolean,
+          value: false,
+          observer: '_handleHeightChanged',
+        },
+        _reviewersPendingRemove: {
+          type: Object,
+          value: {
+            CC: [],
+            REVIEWER: [],
+          },
+        },
+        _sendButtonLabel: {
+          type: String,
+          computed: '_computeSendButtonLabel(canBeStarted)',
+        },
+        _savingComments: Boolean,
+        _reviewersMutated: {
+          type: Boolean,
+          value: false,
+        },
+        _labelsChanged: {
+          type: Boolean,
+          value: false,
+        },
+        _saveTooltip: {
+          type: String,
+          value: ButtonTooltips.SAVE,
+          readOnly: true,
+        },
+        _pluginMessage: {
+          type: String,
+          value: '',
+        },
+        _sendDisabled: {
+          type: Boolean,
+          computed: '_computeSendButtonDisabled(_sendButtonLabel, ' +
             'diffDrafts, draft, _reviewersMutated, _labelsChanged, ' +
             '_includeComments, disabled)',
-        observer: '_sendDisabledChanged',
-      },
-    },
+          observer: '_sendDisabledChanged',
+        },
+      };
+    }
 
-    FocusTarget,
+    get keyBindings() {
+      return {
+        'esc': '_handleEscKey',
+        'ctrl+enter meta+enter': '_handleEnterKey',
+      };
+    }
 
-    behaviors: [
-      Gerrit.BaseUrlBehavior,
-      Gerrit.FireBehavior,
-      Gerrit.KeyboardShortcutBehavior,
-      Gerrit.PatchSetBehavior,
-      Gerrit.RESTClientBehavior,
-    ],
-
-    keyBindings: {
-      'esc': '_handleEscKey',
-      'ctrl+enter meta+enter': '_handleEnterKey',
-    },
-
-    observers: [
-      '_changeUpdated(change.reviewers.*, change.owner)',
-      '_ccsChanged(_ccs.splices)',
-      '_reviewersChanged(_reviewers.splices)',
-    ],
+    static get observers() {
+      return [
+        '_changeUpdated(change.reviewers.*, change.owner)',
+        '_ccsChanged(_ccs.splices)',
+        '_reviewersChanged(_reviewers.splices)',
+      ];
+    }
 
     attached() {
+      super.attached();
       this._getAccount().then(account => {
         this._account = account || {};
       });
-    },
+    }
 
     ready() {
+      super.ready();
       this.$.jsAPI.addElement(this.$.jsAPI.Element.REPLY_DIALOG, this);
-    },
+    }
 
     open(opt_focusTarget) {
       this.knownLatestState = LatestPatchState.CHECKING;
@@ -268,11 +285,11 @@
           this._savingComments = false;
         });
       }
-    },
+    }
 
     focus() {
       this._focusOn(FocusTarget.ANY);
-    },
+    }
 
     getFocusStops() {
       const end = this._sendDisabled ? this.$.cancelButton : this.$.sendButton;
@@ -280,14 +297,14 @@
         start: this.$.reviewers.focusStart,
         end,
       };
-    },
+    }
 
     setLabelValue(label, value) {
       const selectorEl =
           this.$.labelScores.$$(`gr-label-score-row[name="${label}"]`);
       if (!selectorEl) { return; }
       selectorEl.setSelectedValue(value);
-    },
+    }
 
     getLabelValue(label) {
       const selectorEl =
@@ -295,23 +312,23 @@
       if (!selectorEl) { return null; }
 
       return selectorEl.selectedValue;
-    },
+    }
 
     _handleEscKey(e) {
       this.cancel();
-    },
+    }
 
     _handleEnterKey(e) {
       this._submit();
-    },
+    }
 
     _ccsChanged(splices) {
       this._reviewerTypeChanged(splices, ReviewerTypes.CC);
-    },
+    }
 
     _reviewersChanged(splices) {
       this._reviewerTypeChanged(splices, ReviewerTypes.REVIEWER);
-    },
+    }
 
     _reviewerTypeChanged(splices, reviewerType) {
       if (splices && splices.indexSplices) {
@@ -342,7 +359,7 @@
           }
         }
       }
-    },
+    }
 
     _processReviewerChange(indexSplices, type) {
       for (const splice of indexSplices) {
@@ -354,7 +371,7 @@
           this._reviewersPendingRemove[type].push(account);
         }
       }
-    },
+    }
 
     /**
      * Resets the state of the _reviewersPendingRemove object, and removes
@@ -380,7 +397,7 @@
           this._reviewersPendingRemove[type] = [];
         }
       }
-    },
+    }
 
     /**
      * Removes an account from the change, both on the backend and the client.
@@ -404,7 +421,7 @@
           }
         }
       });
-    },
+    }
 
     _mapReviewer(reviewer) {
       let reviewerId;
@@ -416,7 +433,7 @@
         confirmed = reviewer.group.confirmed;
       }
       return {reviewer: reviewerId, confirmed};
-    },
+    }
 
     send(includeComments, startReview) {
       this.$.reporting.time(SEND_REPLY_TIMING_LABEL);
@@ -479,7 +496,7 @@
         this.disabled = false;
         throw err;
       });
-    },
+    }
 
     _focusOn(section) {
       // Safeguard- always want to focus on something.
@@ -497,7 +514,7 @@
         const ccEntry = this.$.ccs.focusStart;
         ccEntry.async(ccEntry.focus);
       }
-    },
+    }
 
     _chooseFocusTarget() {
       // If we are the owner and the reviewers field is empty, focus on that.
@@ -509,7 +526,7 @@
 
       // Default to BODY.
       return FocusTarget.BODY;
-    },
+    }
 
     _handle400Error(response) {
       // A call to _saveReview could fail with a server error if erroneous
@@ -551,11 +568,11 @@
         this.fire('server-error', {response});
         return null; // Means that the error has been handled.
       });
-    },
+    }
 
     _computeHideDraftList(drafts) {
       return Object.keys(drafts || {}).length == 0;
-    },
+    }
 
     _computeDraftsTitle(drafts) {
       let total = 0;
@@ -567,13 +584,13 @@
       if (total == 0) { return ''; }
       if (total == 1) { return '1 Draft'; }
       if (total > 1) { return total + ' Drafts'; }
-    },
+    }
 
     _computeMessagePlaceholder(canBeStarted) {
       return canBeStarted ?
         'Add a note for your reviewers...' :
         'Say something nice...';
-    },
+    }
 
     _changeUpdated(changeRecord, owner) {
       // Polymer 2: check for undefined
@@ -582,7 +599,7 @@
       }
 
       this._rebuildReviewerArrays(changeRecord.base, owner);
-    },
+    }
 
     _rebuildReviewerArrays(change, owner) {
       this._owner = owner;
@@ -614,11 +631,11 @@
 
       this._ccs = ccs;
       this._reviewers = reviewers;
-    },
+    }
 
     _accountOrGroupKey(entry) {
       return entry.id || entry._account_id;
-    },
+    }
 
     /**
      * Generates a function to filter out reviewer/CC entries. When isCCs is
@@ -650,23 +667,23 @@
         }
         return this._reviewers.find(finder) === undefined;
       };
-    },
+    }
 
     _getAccount() {
       return this.$.restAPI.getAccount();
-    },
+    }
 
     _cancelTapHandler(e) {
       e.preventDefault();
       this.cancel();
-    },
+    }
 
     cancel() {
       this.fire('cancel', null, {bubbles: false});
       this.$.textarea.closeDropdown();
       this._purgeReviewersPendingRemove(true);
       this._rebuildReviewerArrays(this.change.reviewers, this._owner);
-    },
+    }
 
     _saveTapHandler(e) {
       e.preventDefault();
@@ -678,12 +695,12 @@
       this.send(this._includeComments, false).then(keepReviewers => {
         this._purgeReviewersPendingRemove(false, keepReviewers);
       });
-    },
+    }
 
     _sendTapHandler(e) {
       e.preventDefault();
       this._submit();
-    },
+    }
 
     _submit() {
       if (!this.$.ccs.submitEntryText()) {
@@ -710,12 +727,12 @@
               detail: {message: `Error submitting review ${err}`},
             }));
           });
-    },
+    }
 
     _saveReview(review, opt_errFn) {
       return this.$.restAPI.saveChangeReview(this.change._number, this.patchNum,
           review, opt_errFn);
-    },
+    }
 
     _reviewerPendingConfirmationUpdated(reviewer) {
       if (reviewer === null) {
@@ -725,7 +742,7 @@
             this._ccPendingConfirmation || this._reviewerPendingConfirmation;
         this.$.reviewerConfirmationOverlay.open();
       }
-    },
+    }
 
     _confirmPendingReviewer() {
       if (this._ccPendingConfirmation) {
@@ -735,7 +752,7 @@
         this.$.reviewers.confirmGroup(this._reviewerPendingConfirmation.group);
         this._focusOn(FocusTarget.REVIEWERS);
       }
-    },
+    }
 
     _cancelPendingReviewer() {
       this._ccPendingConfirmation = null;
@@ -744,7 +761,7 @@
       const target =
           this._ccPendingConfirmation ? FocusTarget.CCS : FocusTarget.REVIEWERS;
       this._focusOn(target);
-    },
+    }
 
     _getStorageLocation() {
       // Tests trigger this method without setting change.
@@ -754,12 +771,12 @@
         patchNum: '@change',
         path: '@change',
       };
-    },
+    }
 
     _loadStoredDraft() {
       const draft = this.$.storage.getDraftComment(this._getStorageLocation());
       return draft ? draft.message : '';
-    },
+    }
 
     _handleAccountTextEntry() {
       // When either of the account entries has input added to the autocomplete,
@@ -767,7 +784,7 @@
       //
       // Note: if the text is removed, the save button will not get disabled.
       this._reviewersMutated = true;
-    },
+    }
 
     _draftChanged(newDraft, oldDraft) {
       this.debounce('store', () => {
@@ -780,37 +797,37 @@
               this.draft);
         }
       }, STORAGE_DEBOUNCE_INTERVAL_MS);
-    },
+    }
 
     _handleHeightChanged(e) {
       this.fire('autogrow');
-    },
+    }
 
     _handleLabelsChanged() {
       this._labelsChanged = Object.keys(
           this.$.labelScores.getLabelValues()).length !== 0;
-    },
+    }
 
     _isState(knownLatestState, value) {
       return knownLatestState === value;
-    },
+    }
 
     _reload() {
       // Load the current change without any patch range.
       location.href = this.getBaseUrl() + '/c/' + this.change._number;
-    },
+    }
 
     _computeSendButtonLabel(canBeStarted) {
       return canBeStarted ? ButtonLabels.START_REVIEW : ButtonLabels.SEND;
-    },
+    }
 
     _computeSendButtonTooltip(canBeStarted) {
       return canBeStarted ? ButtonTooltips.START_REVIEW : ButtonTooltips.SEND;
-    },
+    }
 
     _computeSavingLabelClass(savingComments) {
       return savingComments ? 'saving' : '';
-    },
+    }
 
     _computeSendButtonDisabled(buttonLabel, drafts, text, reviewersMutated,
         labelsChanged, includeComments, disabled) {
@@ -831,7 +848,7 @@
       if (buttonLabel === ButtonLabels.START_REVIEW) { return false; }
       const hasDrafts = includeComments && Object.keys(drafts).length;
       return !hasDrafts && !text.length && !reviewersMutated && !labelsChanged;
-    },
+    }
 
     _computePatchSetWarning(patchNum, labelsChanged) {
       let str = `Patch ${patchNum} is not latest.`;
@@ -839,28 +856,30 @@
         str += ' Voting on a non-latest patch will have no effect.';
       }
       return str;
-    },
+    }
 
     setPluginMessage(message) {
       this._pluginMessage = message;
-    },
+    }
 
     _sendDisabledChanged(sendDisabled) {
       this.dispatchEvent(new CustomEvent('send-disabled-changed'));
-    },
+    }
 
     _getReviewerSuggestionsProvider(change) {
       const provider = GrReviewerSuggestionsProvider.create(this.$.restAPI,
           change._number, Gerrit.SUGGESTIONS_PROVIDERS_USERS_TYPES.REVIEWER);
       provider.init();
       return provider;
-    },
+    }
 
     _getCcSuggestionsProvider(change) {
       const provider = GrReviewerSuggestionsProvider.create(this.$.restAPI,
           change._number, Gerrit.SUGGESTIONS_PROVIDERS_USERS_TYPES.CC);
       provider.init();
       return provider;
-    },
-  });
+    }
+  }
+
+  customElements.define(GrReplyDialog.is, GrReplyDialog);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.js b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.js
index 284f1d6..3cc79fa 100644
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.js
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.js
@@ -17,69 +17,75 @@
 (function() {
   'use strict';
 
-  Polymer({
-    is: 'gr-reviewer-list',
-
+  /**
+    * @appliesMixin Gerrit.FireMixin
+    */
+  class GrReviewerList extends Polymer.mixinBehaviors( [
+    Gerrit.FireBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-reviewer-list'; }
     /**
      * Fired when the "Add reviewer..." button is tapped.
      *
      * @event show-reply-dialog
      */
 
-    properties: {
-      change: Object,
-      disabled: {
-        type: Boolean,
-        value: false,
-        reflectToAttribute: true,
-      },
-      mutable: {
-        type: Boolean,
-        value: false,
-      },
-      reviewersOnly: {
-        type: Boolean,
-        value: false,
-      },
-      ccsOnly: {
-        type: Boolean,
-        value: false,
-      },
-      maxReviewersDisplayed: Number,
+    static get properties() {
+      return {
+        change: Object,
+        disabled: {
+          type: Boolean,
+          value: false,
+          reflectToAttribute: true,
+        },
+        mutable: {
+          type: Boolean,
+          value: false,
+        },
+        reviewersOnly: {
+          type: Boolean,
+          value: false,
+        },
+        ccsOnly: {
+          type: Boolean,
+          value: false,
+        },
+        maxReviewersDisplayed: Number,
 
-      _displayedReviewers: {
-        type: Array,
-        value() { return []; },
-      },
-      _reviewers: {
-        type: Array,
-        value() { return []; },
-      },
-      _showInput: {
-        type: Boolean,
-        value: false,
-      },
-      _addLabel: {
-        type: String,
-        computed: '_computeAddLabel(ccsOnly)',
-      },
-      _hiddenReviewerCount: {
-        type: Number,
-        computed: '_computeHiddenCount(_reviewers, _displayedReviewers)',
-      },
+        _displayedReviewers: {
+          type: Array,
+          value() { return []; },
+        },
+        _reviewers: {
+          type: Array,
+          value() { return []; },
+        },
+        _showInput: {
+          type: Boolean,
+          value: false,
+        },
+        _addLabel: {
+          type: String,
+          computed: '_computeAddLabel(ccsOnly)',
+        },
+        _hiddenReviewerCount: {
+          type: Number,
+          computed: '_computeHiddenCount(_reviewers, _displayedReviewers)',
+        },
 
-      // Used for testing.
-      _lastAutocompleteRequest: Object,
-      _xhrPromise: Object,
-    },
+        // Used for testing.
+        _lastAutocompleteRequest: Object,
+        _xhrPromise: Object,
+      };
+    }
 
-    behaviors: [
-      Gerrit.FireBehavior,
-    ],
-
-    observers: [
-      '_reviewersChanged(change.reviewers.*, change.owner)',
-    ],
+    static get observers() {
+      return [
+        '_reviewersChanged(change.reviewers.*, change.owner)',
+      ];
+    }
 
     /**
      * Converts change.permitted_labels to an array of hashes of label keys to
@@ -100,7 +106,7 @@
         label,
         scores: labels[label].map(v => parseInt(v, 10)),
       }));
-    },
+    }
 
     /**
      * Returns hash of labels to max permitted score.
@@ -114,7 +120,7 @@
                 .map(v => parseInt(v, 10))
                 .reduce((a, b) => Math.max(a, b))}))
           .reduce((acc, i) => Object.assign(acc, i), {});
-    },
+    }
 
     /**
      * Returns max permitted score for reviewer.
@@ -139,7 +145,7 @@
         return 0;
       }
       return NaN;
-    },
+    }
 
     _computeReviewerTooltip(reviewer, change) {
       if (!change || !change.labels) { return ''; }
@@ -160,7 +166,7 @@
       } else {
         return '';
       }
-    },
+    }
 
     _reviewersChanged(changeRecord, owner) {
       // Polymer 2: check for undefined
@@ -194,7 +200,7 @@
       } else {
         this._displayedReviewers = this._reviewers;
       }
-    },
+    }
 
     _computeHiddenCount(reviewers, displayedReviewers) {
       // Polymer 2: check for undefined
@@ -203,7 +209,7 @@
       }
 
       return reviewers.length - displayedReviewers.length;
-    },
+    }
 
     _computeCanRemoveReviewer(reviewer, mutable) {
       if (!mutable) { return false; }
@@ -217,7 +223,7 @@
         }
       }
       return false;
-    },
+    }
 
     _handleRemove(e) {
       e.preventDefault();
@@ -245,7 +251,7 @@
         this.disabled = false;
         throw err;
       });
-    },
+    }
 
     _handleAddTap(e) {
       e.preventDefault();
@@ -257,18 +263,20 @@
         value.ccsOnly = true;
       }
       this.fire('show-reply-dialog', {value});
-    },
+    }
 
     _handleViewAll(e) {
       this._displayedReviewers = this._reviewers;
-    },
+    }
 
     _removeReviewer(id) {
       return this.$.restAPI.removeChangeReviewer(this.change._number, id);
-    },
+    }
 
     _computeAddLabel(ccsOnly) {
       return ccsOnly ? 'Add CC' : 'Add reviewer';
-    },
-  });
+    }
+  }
+
+  customElements.define(GrReviewerList.is, GrReviewerList);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.js b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.js
index 608cbaa..3a6b2df 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.js
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.js
@@ -22,39 +22,42 @@
    *
    * @event thread-list-modified
    */
+  class GrThreadList extends Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element)) {
+    static get is() { return 'gr-thread-list'; }
 
-  Polymer({
-    is: 'gr-thread-list',
-
-    properties: {
+    static get properties() {
+      return {
       /** @type {?} */
-      change: Object,
-      threads: Array,
-      changeNum: String,
-      loggedIn: Boolean,
-      _sortedThreads: {
-        type: Array,
-      },
-      _filteredThreads: {
-        type: Array,
-        computed: '_computeFilteredThreads(_sortedThreads, ' +
+        change: Object,
+        threads: Array,
+        changeNum: String,
+        loggedIn: Boolean,
+        _sortedThreads: {
+          type: Array,
+        },
+        _filteredThreads: {
+          type: Array,
+          computed: '_computeFilteredThreads(_sortedThreads, ' +
             '_unresolvedOnly, _draftsOnly)',
-      },
-      _unresolvedOnly: {
-        type: Boolean,
-        value: false,
-      },
-      _draftsOnly: {
-        type: Boolean,
-        value: false,
-      },
-    },
+        },
+        _unresolvedOnly: {
+          type: Boolean,
+          value: false,
+        },
+        _draftsOnly: {
+          type: Boolean,
+          value: false,
+        },
+      };
+    }
 
-    observers: ['_computeSortedThreads(threads.*)'],
+    static get observers() { return ['_computeSortedThreads(threads.*)']; }
 
     _computeShowDraftToggle(loggedIn) {
       return loggedIn ? 'show' : '';
-    },
+    }
 
     /**
      * Order as follows:
@@ -68,7 +71,7 @@
       const threads = changeRecord.base;
       if (!threads) { return []; }
       this._updateSortedThreads(threads);
-    },
+    }
 
     _updateSortedThreads(threads) {
       this._sortedThreads =
@@ -90,7 +93,7 @@
             }
             return dateCompare ? dateCompare : c1.id.localeCompare(c2.id);
           });
-    },
+    }
 
     _computeFilteredThreads(sortedThreads, unresolvedOnly, draftsOnly) {
       // Polymer 2: check for undefined
@@ -125,7 +128,7 @@
           return c;
         }
       }).map(threadInfo => threadInfo.thread);
-    },
+    }
 
     _getThreadWithSortInfo(thread) {
       const lastComment = thread.comments[thread.comments.length - 1] || {};
@@ -143,7 +146,7 @@
         hasDraft: !!lastComment.__draft,
         updated: lastComment.updated,
       };
-    },
+    }
 
     removeThread(rootId) {
       for (let i = 0; i < this.threads.length; i++) {
@@ -154,11 +157,11 @@
           return;
         }
       }
-    },
+    }
 
     _handleThreadDiscard(e) {
       this.removeThread(e.detail.rootId);
-    },
+    }
 
     _handleCommentsChanged(e) {
       // Reset threads so thread computations occur on deep array changes to
@@ -167,10 +170,12 @@
 
       this.dispatchEvent(new CustomEvent('thread-list-modified',
           {detail: {rootId: e.detail.rootId, path: e.detail.path}}));
-    },
+    }
 
     _isOnParent(side) {
       return !!side;
-    },
-  });
+    }
+  }
+
+  customElements.define(GrThreadList.is, GrThreadList);
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.js b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.js
index 092204a..a3ae1f9 100644
--- a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.js
@@ -27,41 +27,46 @@
     'pull',
   ];
 
-  Polymer({
-    is: 'gr-upload-help-dialog',
-
+  /**
+    * @appliesMixin Gerrit.FireMixin
+    */
+  class GrUploadHelpDialog extends Polymer.mixinBehaviors( [
+    Gerrit.FireBehavior,
+  ], Polymer.GestureEventListeners(
+      Polymer.LegacyElementMixin(
+          Polymer.Element))) {
+    static get is() { return 'gr-upload-help-dialog'; }
     /**
      * Fired when the user presses the close button.
      *
      * @event close
      */
 
-    properties: {
-      revision: Object,
-      targetBranch: String,
-      _commitCommand: {
-        type: String,
-        value: COMMIT_COMMAND,
-        readOnly: true,
-      },
-      _fetchCommand: {
-        type: String,
-        computed: '_computeFetchCommand(revision, ' +
+    static get properties() {
+      return {
+        revision: Object,
+        targetBranch: String,
+        _commitCommand: {
+          type: String,
+          value: COMMIT_COMMAND,
+          readOnly: true,
+        },
+        _fetchCommand: {
+          type: String,
+          computed: '_computeFetchCommand(revision, ' +
             '_preferredDownloadCommand, _preferredDownloadScheme)',
-      },
-      _preferredDownloadCommand: String,
-      _preferredDownloadScheme: String,
-      _pushCommand: {
-        type: String,
-        computed: '_computePushCommand(targetBranch)',
-      },
-    },
-
-    behaviors: [
-      Gerrit.FireBehavior,
-    ],
+        },
+        _preferredDownloadCommand: String,
+        _preferredDownloadScheme: String,
+        _pushCommand: {
+          type: String,
+          computed: '_computePushCommand(targetBranch)',
+        },
+      };
+    }
 
     attached() {
+      super.attached();
       this.$.restAPI.getLoggedIn().then(loggedIn => {
         if (loggedIn) {
           return this.$.restAPI.getPreferences();
@@ -72,13 +77,13 @@
           this._preferredDownloadScheme = prefs.download_scheme;
         }
       });
-    },
+    }
 
     _handleCloseTap(e) {
       e.preventDefault();
       e.stopPropagation();
       this.fire('close', null, {bubbles: false});
-    },
+    }
 
     _computeFetchCommand(revision, preferredDownloadCommand,
         preferredDownloadScheme) {
@@ -126,10 +131,12 @@
       }
 
       return undefined;
-    },
+    }
 
     _computePushCommand(targetBranch) {
       return PUSH_COMMAND_PREFIX + targetBranch;
-    },
-  });
+    }
+  }
+
+  customElements.define(GrUploadHelpDialog.is, GrUploadHelpDialog);
 })();