diff --git a/app/assets/javascripts/discourse/components/edit-category-general.js.es6 b/app/assets/javascripts/discourse/components/edit-category-general.js.es6
new file mode 100644
index 00000000000..66cff47730d
--- /dev/null
+++ b/app/assets/javascripts/discourse/components/edit-category-general.js.es6
@@ -0,0 +1,60 @@
+import { buildCategoryPanel } from 'discourse/components/edit-category-panel';
+import { categoryBadgeHTML } from 'discourse/helpers/category-link';
+
+export default buildCategoryPanel('general', {
+  foregroundColors: ['FFFFFF', '000000'],
+  canSelectParentCategory: Em.computed.not('category.isUncategorizedCategory'),
+
+  // background colors are available as a pipe-separated string
+  backgroundColors: function() {
+    const categories = Discourse.Category.list();
+    return this.siteSettings.category_colors.split("|").map(function(i) { return i.toUpperCase(); }).concat(
+                categories.map(function(c) { return c.color.toUpperCase(); }) ).uniq();
+  }.property(),
+
+  usedBackgroundColors: function() {
+    const categories = Discourse.Category.list();
+    const category = this.get('category');
+
+    // If editing a category, don't include its color:
+    return categories.map(function(c) {
+      return (category.get('id') && category.get('color').toUpperCase() === c.color.toUpperCase()) ? null : c.color.toUpperCase();
+    }, this).compact();
+  }.property('category.id', 'category.color'),
+
+  parentCategories: function() {
+    return Discourse.Category.list().filter(function (c) {
+      return !c.get('parentCategory');
+    });
+  }.property(),
+
+  categoryBadgePreview: function() {
+    const category = this.get('category');
+    const c = Discourse.Category.create({
+      name: category.get('categoryName'),
+      color: category.get('color'),
+      text_color: category.get('text_color'),
+      parent_category_id: parseInt(category.get('parent_category_id'),10),
+      read_restricted: category.get('read_restricted')
+    });
+    return categoryBadgeHTML(c, {link: false});
+  }.property('category.parent_category_id', 'category.categoryName', 'category.color', 'category.text_color'),
+
+
+  // We can change the parent if there are no children
+  subCategories: function() {
+    if (Ember.isEmpty(this.get('category.id'))) { return null; }
+    return Discourse.Category.list().filterBy('parent_category_id', this.get('category.id'));
+  }.property('category.id'),
+
+  showDescription: function() {
+    return !this.get('category.isUncategorizedCategory') && this.get('category.id');
+  }.property('category.isUncategorizedCategory', 'category.id'),
+
+  actions: {
+    showCategoryTopic() {
+      Discourse.URL.routeTo(this.get('category.topic_url'));
+      return false;
+    }
+  }
+});
diff --git a/app/assets/javascripts/discourse/components/edit-category-images.js.es6 b/app/assets/javascripts/discourse/components/edit-category-images.js.es6
new file mode 100644
index 00000000000..885ee5835b2
--- /dev/null
+++ b/app/assets/javascripts/discourse/components/edit-category-images.js.es6
@@ -0,0 +1,2 @@
+import { buildCategoryPanel } from 'discourse/components/edit-category-panel';
+export default buildCategoryPanel('images');
diff --git a/app/assets/javascripts/discourse/components/edit-category-panel.js.es6 b/app/assets/javascripts/discourse/components/edit-category-panel.js.es6
new file mode 100644
index 00000000000..5cf7a0e1f8f
--- /dev/null
+++ b/app/assets/javascripts/discourse/components/edit-category-panel.js.es6
@@ -0,0 +1,11 @@
+const EditCategoryPanel = Ember.Component.extend({
+  classNameBindings: [':modal-tab', 'activeTab::invisible'],
+});
+
+export default EditCategoryPanel;
+
+export function buildCategoryPanel(tab, extras) {
+  return EditCategoryPanel.extend({
+    activeTab: Ember.computed.equal('selectedTab', tab)
+  }, extras || {});
+}
diff --git a/app/assets/javascripts/discourse/components/edit-category-security.js.es6 b/app/assets/javascripts/discourse/components/edit-category-security.js.es6
new file mode 100644
index 00000000000..593a604e7ad
--- /dev/null
+++ b/app/assets/javascripts/discourse/components/edit-category-security.js.es6
@@ -0,0 +1,22 @@
+import { buildCategoryPanel } from 'discourse/components/edit-category-panel';
+
+export default buildCategoryPanel('security', {
+  editingPermissions: false,
+  selectedGroup: null,
+  selectedPermission: null,
+
+  actions: {
+    editPermissions() {
+      this.set('editingPermissions', true);
+    },
+
+    addPermission(group, id) {
+      this.get('category').addPermission({group_name: group + "",
+                                       permission: Discourse.PermissionType.create({id})});
+    },
+
+    removePermission(permission) {
+      this.get('category').removePermission(permission);
+    },
+  }
+});
diff --git a/app/assets/javascripts/discourse/components/edit-category-settings.js.es6 b/app/assets/javascripts/discourse/components/edit-category-settings.js.es6
new file mode 100644
index 00000000000..3bba6b1b242
--- /dev/null
+++ b/app/assets/javascripts/discourse/components/edit-category-settings.js.es6
@@ -0,0 +1,6 @@
+import { buildCategoryPanel } from 'discourse/components/edit-category-panel';
+
+export default buildCategoryPanel('settings', {
+  emailInEnabled: Discourse.computed.setting('email_in'),
+  showPositionInput: Discourse.computed.setting('fixed_category_positions'),
+});
diff --git a/app/assets/javascripts/discourse/components/edit-category-tab.js.es6 b/app/assets/javascripts/discourse/components/edit-category-tab.js.es6
index 0eaa00ff84c..27bda38cfa9 100644
--- a/app/assets/javascripts/discourse/components/edit-category-tab.js.es6
+++ b/app/assets/javascripts/discourse/components/edit-category-tab.js.es6
@@ -5,8 +5,8 @@ export default Em.Component.extend({
   active: Discourse.computed.propertyEqual('selectedTab', 'tab'),
   title: Discourse.computed.i18n('tab', 'category.%@'),
 
-  _insertInParent: function() {
-    this.get('parentView.panels').addObject(this.get('tab'));
+  _addToCollection: function() {
+    this.get('panels').addObject('edit-category-' + this.get('tab'));
   }.on('didInsertElement'),
 
   actions: {
diff --git a/app/assets/javascripts/discourse/controllers/edit-category.js.es6 b/app/assets/javascripts/discourse/controllers/edit-category.js.es6
index ad1e1f2351b..8bd47259b95 100644
--- a/app/assets/javascripts/discourse/controllers/edit-category.js.es6
+++ b/app/assets/javascripts/discourse/controllers/edit-category.js.es6
@@ -1,28 +1,16 @@
 import ModalFunctionality from 'discourse/mixins/modal-functionality';
 import ObjectController from 'discourse/controllers/object';
-import { categoryBadgeHTML } from 'discourse/helpers/category-link';
 
 // Modal for editing / creating a category
 export default ObjectController.extend(ModalFunctionality, {
-  foregroundColors: ['FFFFFF', '000000'],
-  editingPermissions: false,
   selectedTab: null,
   saving: false,
   deleting: false,
+  panels: null,
 
-  parentCategories: function() {
-    return Discourse.Category.list().filter(function (c) {
-      return !c.get('parentCategory');
-    });
-  }.property(),
-
-  // We can change the parent if there are no children
-  subCategories: function() {
-    if (Em.isEmpty(this.get('model.id'))) { return null; }
-    return Discourse.Category.list().filterBy('parent_category_id', this.get('model.id'));
-  }.property('model.id'),
-
-  canSelectParentCategory: Em.computed.not('model.isUncategorizedCategory'),
+  _initPanels: function() {
+    this.set('panels', []);
+  }.on('init'),
 
   onShow() {
     this.changeSize();
@@ -55,46 +43,10 @@ export default ObjectController.extend(ModalFunctionality, {
     return false;
   }.property('saving', 'model.name', 'model.color', 'deleting'),
 
-  emailInEnabled: Discourse.computed.setting('email_in'),
-
   deleteDisabled: function() {
     return (this.get('deleting') || this.get('saving') || false);
   }.property('disabled', 'saving', 'deleting'),
 
-  colorStyle: function() {
-    return "background-color: #" + this.get('model.color') + "; color: #" + this.get('model.text_color') + ";";
-  }.property('model.color', 'model.text_color'),
-
-  categoryBadgePreview: function() {
-    const model = this.get('model');
-    const c = Discourse.Category.create({
-      name: model.get('categoryName'),
-      color: model.get('color'),
-      text_color: model.get('text_color'),
-      parent_category_id: parseInt(model.get('parent_category_id'),10),
-      read_restricted: model.get('read_restricted')
-    });
-    return categoryBadgeHTML(c, {link: false});
-  }.property('model.parent_category_id', 'model.categoryName', 'model.color', 'model.text_color'),
-
-  // background colors are available as a pipe-separated string
-  backgroundColors: function() {
-    const categories = Discourse.Category.list();
-    return Discourse.SiteSettings.category_colors.split("|").map(function(i) { return i.toUpperCase(); }).concat(
-                categories.map(function(c) { return c.color.toUpperCase(); }) ).uniq();
-  }.property('Discourse.SiteSettings.category_colors'),
-
-  usedBackgroundColors: function() {
-    const categories = Discourse.Category.list();
-
-    const currentCat = this.get('model');
-
-    return categories.map(function(c) {
-      // If editing a category, don't include its color:
-      return (currentCat.get('id') && currentCat.get('color').toUpperCase() === c.color.toUpperCase()) ? null : c.color.toUpperCase();
-    }, this).compact();
-  }.property('model.id', 'model.color'),
-
   categoryName: function() {
     const name = this.get('name') || "";
     return name.trim().length > 0 ? name : I18n.t("preview");
@@ -106,32 +58,7 @@ export default ObjectController.extend(ModalFunctionality, {
     return this.get('model.id') ? "category.save" : "category.create";
   }.property('saving', 'model.id'),
 
-  showDescription: function() {
-    return !this.get('model.isUncategorizedCategory') && this.get('model.id');
-  }.property('model.isUncategorizedCategory', 'model.id'),
-
-  showPositionInput: Discourse.computed.setting('fixed_category_positions'),
-
   actions: {
-    showCategoryTopic() {
-      this.send('closeModal');
-      Discourse.URL.routeTo(this.get('model.topic_url'));
-      return false;
-    },
-
-    editPermissions() {
-      this.set('editingPermissions', true);
-    },
-
-    addPermission(group, id) {
-      this.get('model').addPermission({group_name: group + "",
-                                       permission: Discourse.PermissionType.create({id})});
-    },
-
-    removePermission(permission) {
-      this.get('model').removePermission(permission);
-    },
-
     saveCategory() {
       const self = this,
           model = this.get('model'),
diff --git a/app/assets/javascripts/discourse/templates/modal/edit-category-general.hbs b/app/assets/javascripts/discourse/templates/components/edit-category-general.hbs
similarity index 62%
rename from app/assets/javascripts/discourse/templates/modal/edit-category-general.hbs
rename to app/assets/javascripts/discourse/templates/components/edit-category-general.hbs
index 21c724abee2..9f93466ae1a 100644
--- a/app/assets/javascripts/discourse/templates/modal/edit-category-general.hbs
+++ b/app/assets/javascripts/discourse/templates/components/edit-category-general.hbs
@@ -2,11 +2,11 @@
   <section class='field'>
     <section class="field-item">
       <label>{{i18n 'category.name'}}</label>
-      {{text-field value=model.name placeholderKey="category.name_placeholder" maxlength="50"}}
+      {{text-field value=category.name placeholderKey="category.name_placeholder" maxlength="50"}}
     </section>
     <section class="field-item">
       <label>{{i18n 'category.slug'}}</label>
-      {{text-field value=model.slug placeholderKey="category.slug_placeholder" maxlength="255"}}
+      {{text-field value=category.slug placeholderKey="category.slug_placeholder" maxlength="255"}}
     </section>
   </section>
 
@@ -14,12 +14,12 @@
     <section class='field'>
       {{#if subCategories}}
         <label>{{i18n 'categories.subcategories'}}</label>
-        {{#each s in subCategories}}
+        {{#each subCategories as |s|}}
           {{category-badge s hideParent="true"}}
         {{/each}}
       {{else}}
         <label>{{i18n 'category.parent'}}</label>
-        {{category-chooser valueAttribute="id" value=model.parent_category_id categories=parentCategories rootNone=true}}
+        {{category-chooser valueAttribute="id" value=category.parent_category_id categories=parentCategories rootNone=true}}
       {{/if}}
     </section>
   {{/if}}
@@ -27,12 +27,12 @@
   {{#if showDescription}}
     <section class='field'>
       <label>{{i18n 'category.description'}}</label>
-      {{#if model.description}}
-        {{{model.description}}}
+      {{#if category.description}}
+        {{{category.description}}}
       {{else}}
         {{i18n 'category.no_description'}}
       {{/if}}
-      {{#if model.topic_url}}
+      {{#if category.topic_url}}
         <br/>
         {{d-button class="btn-small" action="showCategoryTopic" icon="pencil" label="category.change_in_category_topic"}}
       {{/if}}
@@ -46,14 +46,14 @@
 
       <div class='input-prepend input-append' style="margin-top: 10px;">
         <span class='color-title'>{{i18n 'category.background_color'}}:</span>
-        <span class='add-on'>#</span>{{text-field value=model.color placeholderKey="category.color_placeholder" maxlength="6"}}
-        {{color-picker colors=backgroundColors usedColors=usedBackgroundColors value=model.color}}
+        <span class='add-on'>#</span>{{text-field value=category.color placeholderKey="category.color_placeholder" maxlength="6"}}
+        {{color-picker colors=backgroundColors usedColors=usedBackgroundColors value=category.color}}
       </div>
 
       <div class='input-prepend input-append'>
         <span class='color-title'>{{i18n 'category.foreground_color'}}:</span>
-        <span class='add-on'>#</span>{{text-field value=model.text_color placeholderKey="category.color_placeholder" maxlength="6"}}
-        {{color-picker colors=foregroundColors value=model.text_color id='edit-text-color'}}
+        <span class='add-on'>#</span>{{text-field value=category.text_color placeholderKey="category.color_placeholder" maxlength="6"}}
+        {{color-picker colors=foregroundColors value=category.text_color id='edit-text-color'}}
       </div>
     </div>
   </section>
diff --git a/app/assets/javascripts/discourse/templates/modal/edit-category-images.hbs b/app/assets/javascripts/discourse/templates/components/edit-category-images.hbs
similarity index 52%
rename from app/assets/javascripts/discourse/templates/modal/edit-category-images.hbs
rename to app/assets/javascripts/discourse/templates/components/edit-category-images.hbs
index c6cac30f593..f4d7995dfdc 100644
--- a/app/assets/javascripts/discourse/templates/modal/edit-category-images.hbs
+++ b/app/assets/javascripts/discourse/templates/components/edit-category-images.hbs
@@ -1,9 +1,9 @@
 <section class='field'>
   <label>{{i18n 'category.logo'}}</label>
-  {{image-uploader imageUrl=model.logo_url type="category_logo"}}
+  {{image-uploader imageUrl=category.logo_url type="category_logo"}}
 </section>
 
 <section class='field'>
   <label>{{i18n 'category.background_image'}}</label>
-  {{image-uploader imageUrl=model.background_url type="category_background"}}
+  {{image-uploader imageUrl=category.background_url type="category_background"}}
 </section>
diff --git a/app/assets/javascripts/discourse/templates/modal/edit-category-security.hbs b/app/assets/javascripts/discourse/templates/components/edit-category-security.hbs
similarity index 62%
rename from app/assets/javascripts/discourse/templates/modal/edit-category-security.hbs
rename to app/assets/javascripts/discourse/templates/components/edit-category-security.hbs
index 99c8a98a636..02361e3cf7b 100644
--- a/app/assets/javascripts/discourse/templates/modal/edit-category-security.hbs
+++ b/app/assets/javascripts/discourse/templates/components/edit-category-security.hbs
@@ -1,19 +1,19 @@
 <section class='field'>
   <ul class='permission-list'>
-    {{#each model.permissions as |p|}}
+    {{#each category.permissions as |p|}}
       <li>
         <span class="name"><span class="badge-group">{{p.group_name}}</span></span>
         {{{i18n "category.can"}}}
         <span class="permission">{{p.permission.description}}</span>
-        {{#if controller.editingPermissions}}
-          <a {{action "removePermission" p}}><i class="fa fa-times-circle"></i></a>
+        {{#if editingPermissions}}
+        <a href {{action "removePermission" p}}>{{fa-icon "times-circle"}}</a>
         {{/if}}
       </li>
     {{/each}}
   </ul>
-  {{#if controller.editingPermissions}}
-    {{view 'select' content=availableGroups value=selectedGroup}}
-    {{view 'select' class="permission-selector" optionValuePath="content.id" optionLabelPath="content.description" content=availablePermissions value=selectedPermission}}
+  {{#if editingPermissions}}
+    {{view 'select' content=category.availableGroups value=selectedGroup}}
+    {{view 'select' class="permission-selector" optionValuePath="content.id" optionLabelPath="content.description" content=category.availablePermissions value=selectedPermission}}
     <button {{action "addPermission" selectedGroup selectedPermission}} class="btn btn-small">{{i18n 'category.add_permission'}}</button>
   {{else}}
     <button {{action "editPermissions"}} class="btn btn-small">{{i18n 'category.edit_permissions'}}</button>
diff --git a/app/assets/javascripts/discourse/templates/modal/edit-category-settings.hbs b/app/assets/javascripts/discourse/templates/components/edit-category-settings.hbs
similarity index 72%
rename from app/assets/javascripts/discourse/templates/modal/edit-category-settings.hbs
rename to app/assets/javascripts/discourse/templates/components/edit-category-settings.hbs
index b6b08f881fb..9dab35610f3 100644
--- a/app/assets/javascripts/discourse/templates/modal/edit-category-settings.hbs
+++ b/app/assets/javascripts/discourse/templates/components/edit-category-settings.hbs
@@ -1,13 +1,13 @@
 <section class='field'>
-  {{auto-close-form autoCloseTime=model.auto_close_hours
-                    autoCloseBasedOnLastPost=model.auto_close_based_on_last_post
+  {{auto-close-form autoCloseTime=category.auto_close_hours
+                    autoCloseBasedOnLastPost=category.auto_close_based_on_last_post
                     limited="true" }}
 </section>
 
 <section class='field'>
   <div class="allow-badges">
     <div>
-      {{input type="checkbox" checked=model.allow_badges}}
+      {{input type="checkbox" checked=category.allow_badges}}
       {{i18n 'category.allow_badges_label'}}
     </div>
   </div>
@@ -19,11 +19,11 @@
       <div>
         <i class="fa fa-envelope-o"></i>
         {{i18n 'category.email_in'}}
-        {{text-field value=email_in}}
+        {{text-field value=category.email_in}}
       </div>
       <div>
         <label class="checkbox-label">
-          {{input type="checkbox" checked=email_in_allow_strangers}}
+          {{input type="checkbox" checked=category.email_in_allow_strangers}}
           {{i18n 'category.email_in_allow_strangers'}}
         </label>
       </div>
@@ -37,7 +37,7 @@
 <section class='field'>
   {{#if showPositionInput}}
     <label>{{i18n 'category.position'}}</label>
-    {{text-field value=position class="position-input"}}
+    {{text-field value=category.position class="position-input"}}
   {{else}}
     {{i18n 'category.position_disabled'}}
     <a href="/admin/site_settings/category/basic">{{i18n 'category.position_disabled_click'}}</a>
diff --git a/app/assets/javascripts/discourse/templates/modal/edit-category.hbs b/app/assets/javascripts/discourse/templates/modal/edit-category.hbs
index ac5ff05850c..3075cadc383 100644
--- a/app/assets/javascripts/discourse/templates/modal/edit-category.hbs
+++ b/app/assets/javascripts/discourse/templates/modal/edit-category.hbs
@@ -1,16 +1,16 @@
 <div>
   <ul class="nav nav-pills">
-    {{edit-category-tab selectedTab=selectedTab tab="general"}}
+    {{edit-category-tab panels=panels selectedTab=selectedTab tab="general"}}
     {{#unless model.isUncategorizedCategory}}
-      {{edit-category-tab selectedTab=selectedTab tab="security"}}
+      {{edit-category-tab panels=panels selectedTab=selectedTab tab="security"}}
     {{/unless}}
-    {{edit-category-tab selectedTab=selectedTab tab="settings"}}
-    {{edit-category-tab selectedTab=selectedTab tab="images"}}
+    {{edit-category-tab panels=panels selectedTab=selectedTab tab="settings"}}
+    {{edit-category-tab panels=panels selectedTab=selectedTab tab="images"}}
   </ul>
 
   <div class="modal-body">
-    {{#each view.panels as |tab|}}
-      {{view 'edit-category-panel' tab=tab}}
+    {{#each panels as |tab|}}
+      {{component tab selectedTab=selectedTab category=model}}
     {{/each}}
   </div>
 
diff --git a/app/assets/javascripts/discourse/views/edit-category-panel.js.es6 b/app/assets/javascripts/discourse/views/edit-category-panel.js.es6
deleted file mode 100644
index fcf77c5763e..00000000000
--- a/app/assets/javascripts/discourse/views/edit-category-panel.js.es6
+++ /dev/null
@@ -1,9 +0,0 @@
-export default Em.View.extend({
-  classNameBindings: [':modal-tab', 'invisible'],
-  invisible: Discourse.computed.propertyNotEqual('controller.selectedTab', 'tab'),
-
-  templateName: function() {
-    return "modal/edit-category-" + this.get('tab');
-  }.property('tab')
-});
-
diff --git a/app/assets/javascripts/discourse/views/edit-category.js.es6 b/app/assets/javascripts/discourse/views/edit-category.js.es6
deleted file mode 100644
index ea93cc99bef..00000000000
--- a/app/assets/javascripts/discourse/views/edit-category.js.es6
+++ /dev/null
@@ -1,9 +0,0 @@
-import ModalBodyView from "discourse/views/modal-body";
-
-export default ModalBodyView.extend({
-  templateName: 'modal/edit-category',
-
-  _initializePanels: function() {
-    this.set('panels', []);
-  }.on('init')
-});
diff --git a/app/assets/javascripts/main_include.js b/app/assets/javascripts/main_include.js
index 83e3490976d..67de20ffe60 100644
--- a/app/assets/javascripts/main_include.js
+++ b/app/assets/javascripts/main_include.js
@@ -44,6 +44,7 @@
 //= require ./discourse/views/flag
 //= require ./discourse/views/cloaked
 //= require ./discourse/components/combo-box
+//= require ./discourse/components/edit-category-panel
 //= require ./discourse/views/button
 //= require ./discourse/components/search-result
 //= require ./discourse/components/dropdown-button