diff --git a/app/assets/javascripts/app/app.js b/app/assets/javascripts/app/app.js
index 7c18d6fb49c8592198471273c8b0d7f1aae3837b..4d42b6b0cdfe80bbe654f449c8eb1dbbfb26a2ca 100644
--- a/app/assets/javascripts/app/app.js
+++ b/app/assets/javascripts/app/app.js
@@ -123,6 +123,7 @@ var app = {
     });
     app.sidebar = new app.views.Sidebar();
     app.backToTop = new app.views.BackToTop({el: $(document)});
+    app.flashMessages = new app.views.FlashMessages({el: $("#flash-container")});
   },
 
   /* mixpanel wrapper function */
diff --git a/app/assets/javascripts/app/models/post/interactions.js b/app/assets/javascripts/app/models/post/interactions.js
index 3913b1fd0a92032e491b8f95f83e0e7177f8d306..fdf38e959e06dbe169b6e884ecc359ad9c36d375 100644
--- a/app/assets/javascripts/app/models/post/interactions.js
+++ b/app/assets/javascripts/app/models/post/interactions.js
@@ -87,11 +87,7 @@ app.models.Post.Interactions = Backbone.Model.extend({
     var self = this;
 
     this.comments.make(text).fail(function () {
-      var flash = new Diaspora.Widgets.FlashMessages();
-      flash.render({
-        success: false,
-        notice: Diaspora.I18n.t("failed_to_post_message")
-      });
+      app.flashMessages.error(Diaspora.I18n.t("failed_to_post_message"));
     }).done(function() {
       self.trigger('change'); //updates after sync
     });
@@ -102,16 +98,11 @@ app.models.Post.Interactions = Backbone.Model.extend({
   },
 
   reshare : function(){
-    var interactions = this
-      , reshare = this.post.reshare()
-      , flash = new Diaspora.Widgets.FlashMessages();
+    var interactions = this;
 
-    reshare.save()
+    this.post.reshare().save()
       .done(function(reshare) {
-        flash.render({
-          success: true,
-          notice: Diaspora.I18n.t("reshares.successful")
-        });
+          app.flashMessages.success(Diaspora.I18n.t("reshares.successful"));
         interactions.reshares.add(reshare);
         if (app.stream && /^\/(?:stream|activity|aspects)/.test(app.stream.basePath())) {
           app.stream.addNow(reshare);
@@ -119,10 +110,7 @@ app.models.Post.Interactions = Backbone.Model.extend({
         interactions.trigger("change");
       })
       .fail(function(){
-        flash.render({
-          success: false,
-          notice: Diaspora.I18n.t("reshares.duplicate")
-        });
+        app.flashMessages.error(Diaspora.I18n.t("reshares.duplicate"));
       });
 
     app.instrument("track", "Reshare");
diff --git a/app/assets/javascripts/app/pages/profile.js b/app/assets/javascripts/app/pages/profile.js
index 3f9bb030a09eb1d32a7ceb998531cd14224524b7..a16b7f27f9ada727c09dcd20378517654f8927a1 100644
--- a/app/assets/javascripts/app/pages/profile.js
+++ b/app/assets/javascripts/app/pages/profile.js
@@ -2,45 +2,47 @@
 
 app.pages.Profile = app.views.Base.extend({
   events: {
-    'click #block_user_button': 'blockPerson',
-    'click #unblock_user_button': 'unblockPerson'
+    "click #block_user_button": "blockPerson",
+    "click #unblock_user_button": "unblockPerson"
   },
 
   subviews: {
-    '#profile': 'sidebarView',
-    '.profile_header': 'headerView',
-    '#main_stream': 'streamView'
+    "#profile": "sidebarView",
+    ".profile_header": "headerView",
+    "#main_stream": "streamView"
   },
 
-  tooltipSelector: '.profile_button .profile-header-icon, .sharing_message_container',
+  tooltipSelector: ".profile_button .profile-header-icon, .sharing_message_container",
 
   initialize: function(opts) {
     if( !this.model ) {
       this._populateModel(opts);
     }
 
-    if( app.hasPreload('photos') )
-      this.photos = app.parsePreload('photos');  // we don't interact with it, so no model
-    if( app.hasPreload('contacts') )
-      this.contacts = app.parsePreload('contacts');  // we don't interact with it, so no model
+    if(app.hasPreload("photos")){
+      this.photos = app.parsePreload("photos");
+    }
+    if(app.hasPreload("contacts")){
+      this.contacts = app.parsePreload("contacts");
+    }
 
-    this.streamCollection = _.has(opts, 'streamCollection') ? opts.streamCollection : null;
-    this.streamViewClass = _.has(opts, 'streamView') ? opts.streamView : null;
+    this.streamCollection = _.has(opts, "streamCollection") ? opts.streamCollection : null;
+    this.streamViewClass = _.has(opts, "streamView") ? opts.streamView : null;
 
-    this.model.on('change', this.render, this);
-    this.model.on('sync', this._done, this);
+    this.model.on("change", this.render, this);
+    this.model.on("sync", this._done, this);
 
     // bind to global events
-    var id = this.model.get('id');
-    app.events.on('person:block:'+id, this.reload, this);
-    app.events.on('person:unblock:'+id, this.reload, this);
-    app.events.on('aspect:create', this.reload, this);
-    app.events.on('aspect_membership:update', this.reload, this);
+    var id = this.model.get("id");
+    app.events.on("person:block:"+id, this.reload, this);
+    app.events.on("person:unblock:"+id, this.reload, this);
+    app.events.on("aspect:create", this.reload, this);
+    app.events.on("aspect_membership:update", this.reload, this);
   },
 
   _populateModel: function(opts) {
-    if( app.hasPreload('person') ) {
-      this.model = new app.models.Person(app.parsePreload('person'));
+    if( app.hasPreload("person") ) {
+      this.model = new app.models.Person(app.parsePreload("person"));
     } else if(opts && opts.person_id) {
       this.model = new app.models.Person({guid: opts.person_id});
       this.model.fetch();
@@ -50,14 +52,18 @@ app.pages.Profile = app.views.Base.extend({
   },
 
   sidebarView: function() {
-    if( !this.model.has('profile') ) return false;
+    if(!this.model.has("profile")){
+      return false;
+    }
     return new app.views.ProfileSidebar({
-      model: this.model,
+      model: this.model
     });
   },
 
   headerView: function() {
-    if( !this.model.has('profile') ) return false;
+    if(!this.model.has("profile")){
+      return false;
+    }
     return new app.views.ProfileHeader({
       model: this.model,
       photos: this.photos,
@@ -66,12 +72,14 @@ app.pages.Profile = app.views.Base.extend({
   },
 
   streamView: function() {
-    if( !this.model.has('profile') ) return false;
+    if(!this.model.has("profile")){
+      return false;
+    }
     if( this.model.isBlocked() ) {
-      $('#main_stream').empty().html(
+      $("#main_stream").empty().html(
         '<div class="dull">'+
-        Diaspora.I18n.t('profile.ignoring', {name: this.model.get('name')}) +
-        '</div>');
+        Diaspora.I18n.t("profile.ignoring", {name: this.model.get("name")}) +
+        "</div>");
       return false;
     }
 
@@ -85,7 +93,7 @@ app.pages.Profile = app.views.Base.extend({
     });
     app.stream.fetch();
 
-    if( this.model.get('is_own_profile') ) {
+    if( this.model.get("is_own_profile") ) {
       app.publisher = new app.views.Publisher({collection : app.stream.items});
     }
 
@@ -93,14 +101,13 @@ app.pages.Profile = app.views.Base.extend({
   },
 
   blockPerson: function() {
-    if( !confirm(Diaspora.I18n.t('ignore_user')) ) return;
+    if(!confirm(Diaspora.I18n.t("ignore_user"))){
+      return;
+    }
 
     var block = this.model.block();
     block.fail(function() {
-      Diaspora.page.flashMessages.render({
-        success: false,
-        notice: Diaspora.I18n.t('ignore_failed')
-      });
+      app.flashMessages.error(Diaspora.I18n.t("ignore_failed"));
     });
 
     return false;
@@ -109,21 +116,18 @@ app.pages.Profile = app.views.Base.extend({
   unblockPerson: function() {
     var block = this.model.unblock();
     block.fail(function() {
-      Diaspora.page.flashMessages.render({
-        success: false,
-        notice: Diaspora.I18.t('unblock_failed')
-      });
+      app.flashMessages.error(Diaspora.I18.t("unblock_failed"));
     });
     return false;
   },
 
   reload: function() {
-    this.$('#profile').addClass('loading');
+    this.$("#profile").addClass("loading");
     this.model.fetch();
   },
 
   _done: function() {
-    this.$('#profile').removeClass('loading');
+    this.$("#profile").removeClass("loading");
   }
 });
 // @license-end
diff --git a/app/assets/javascripts/app/views.js b/app/assets/javascripts/app/views.js
index 4b161422de270d0f93f9d4c9a5dc4ebd1b7d7c0c..f92b043120ccb0e5514976f85e86227d22d48968 100644
--- a/app/assets/javascripts/app/views.js
+++ b/app/assets/javascripts/app/views.js
@@ -105,16 +105,10 @@ app.views.Base = Backbone.View.extend({
     var report = new app.models.Report();
     report.save(data, {
       success: function() {
-        Diaspora.page.flashMessages.render({
-          success: true,
-          notice: Diaspora.I18n.t('report.status.created')
-        });
+        app.flashMessages.success(Diaspora.I18n.t("report.status.created"));
       },
       error: function() {
-        Diaspora.page.flashMessages.render({
-          success: false,
-          notice: Diaspora.I18n.t('report.status.exists')
-        });
+        app.flashMessages.error(Diaspora.I18n.t("report.status.exists"));
       }
     });
   },
@@ -124,21 +118,17 @@ app.views.Base = Backbone.View.extend({
   destroyModel: function(evt) {
     evt && evt.preventDefault();
     var self = this;
-    var url = this.model.urlRoot + '/' + this.model.id;
+    var url = this.model.urlRoot + "/" + this.model.id;
 
     if( confirm(_.result(this, "destroyConfirmMsg")) ) {
-      this.$el.addClass('deleting');
+      this.$el.addClass("deleting");
       this.model.destroy({ url: url })
         .done(function() {
           self.remove();
         })
         .fail(function() {
-          self.$el.removeClass('deleting');
-          var flash = new Diaspora.Widgets.FlashMessages();
-          flash.render({
-            success: false,
-            notice: Diaspora.I18n.t('failed_to_remove')
-          });
+          self.$el.removeClass("deleting");
+          app.flashMessages.error(Diaspora.I18n.t("failed_to_remove"));
         });
     }
   },
diff --git a/app/assets/javascripts/app/views/aspect_create_view.js b/app/assets/javascripts/app/views/aspect_create_view.js
index fa9de946ca66a860a6172fe6b99f233e33ecf8c3..325c874bc3392bb5f244b819b0d11ad910105959 100644
--- a/app/assets/javascripts/app/views/aspect_create_view.js
+++ b/app/assets/javascripts/app/views/aspect_create_view.js
@@ -52,18 +52,12 @@ app.views.AspectCreate = app.views.Base.extend({
 
       self.modal.modal("hide");
       app.events.trigger("aspect:create", aspectId);
-      Diaspora.page.flashMessages.render({
-        "success": true,
-        "notice": Diaspora.I18n.t("aspects.create.success", {"name": aspectName})
-      });
+      app.flashMessages.success(Diaspora.I18n.t("aspects.create.success", {"name": aspectName}));
     });
 
     aspect.on("error", function() {
       self.modal.modal("hide");
-      Diaspora.page.flashMessages.render({
-        "success": false,
-        "notice": Diaspora.I18n.t("aspects.create.failure")
-      });
+      app.flashMessages.error(Diaspora.I18n.t("aspects.create.failure"));
     });
     return aspect.save();
   }
diff --git a/app/assets/javascripts/app/views/aspect_membership_view.js b/app/assets/javascripts/app/views/aspect_membership_view.js
index bbf81d74965cb5f049f97c4a11204553c136ba37..7b9516534988ccf34d7777f4e30a940d5bc3e62e 100644
--- a/app/assets/javascripts/app/views/aspect_membership_view.js
+++ b/app/assets/javascripts/app/views/aspect_membership_view.js
@@ -89,7 +89,7 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
     if( this.dropdown.find("li.selected").length === 0 ) {
       var msg = Diaspora.I18n.t("aspect_dropdown.started_sharing_with", { "name": this._name() });
       startSharing = true;
-      Diaspora.page.flashMessages.render({ "success": true, "notice": msg });
+      app.flashMessages.success(msg);
     }
 
     app.events.trigger("aspect_membership:create", {
@@ -110,7 +110,7 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
     this.dropdown.closest('.aspect_membership_dropdown').removeClass('open'); // close the dropdown
 
     var msg = Diaspora.I18n.t(msg_id, { 'name': this._name() });
-    Diaspora.page.flashMessages.render({ 'success':false, 'notice':msg });
+    app.flashMessages.error(msg);
   },
 
   // remove the membership with the given id
@@ -143,7 +143,7 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
     if( this.dropdown.find("li.selected").length === 0 ) {
       var msg = Diaspora.I18n.t("aspect_dropdown.stopped_sharing_with", { "name": this._name() });
       stopSharing = true;
-      Diaspora.page.flashMessages.render({ "success": true, "notice": msg });
+      app.flashMessages.success(msg);
     }
 
     app.events.trigger("aspect_membership:destroy", {
diff --git a/app/assets/javascripts/app/views/contact_view.js b/app/assets/javascripts/app/views/contact_view.js
index 5277d65cc0531883bc1e4d26ffbd523afbd68e31..d48ce6499737aa1ac5d5de2c5ebcbcee5096870e 100644
--- a/app/assets/javascripts/app/views/contact_view.js
+++ b/app/assets/javascripts/app/views/contact_view.js
@@ -19,7 +19,6 @@ app.views.Contact = app.views.Base.extend({
   },
 
   postRenderTemplate: function() {
-    var self = this;
     var dropdownEl = this.$('.aspect_membership_dropdown.placeholder');
     if( dropdownEl.length === 0 ) {
       return;
@@ -54,7 +53,7 @@ app.views.Contact = app.views.Base.extend({
       },
       error: function(){
         var msg = Diaspora.I18n.t("contacts.error_add", { "name": self.model.get("person").name });
-        Diaspora.page.flashMessages.render({ "success": false, "notice": msg });
+        app.flashMessages.error(msg);
       }
     });
   },
@@ -78,7 +77,7 @@ app.views.Contact = app.views.Base.extend({
         },
         error: function(){
           var msg = Diaspora.I18n.t("contacts.error_remove", { "name": self.model.get("person").name });
-          Diaspora.page.flashMessages.render({ "success": false, "notice": msg });
+          app.flashMessages.error(msg);
         }
       });
   }
diff --git a/app/assets/javascripts/app/views/feedback_view.js b/app/assets/javascripts/app/views/feedback_view.js
index 938469bbb04c98ec893ec49b31b3432f0705e692..70bf4ca6d166191c9e98de3e7b22a02373624ccd 100644
--- a/app/assets/javascripts/app/views/feedback_view.js
+++ b/app/assets/javascripts/app/views/feedback_view.js
@@ -11,13 +11,13 @@ app.views.Feedback = app.views.Base.extend({
 
     "click .post_report" : "report",
     "click .block_user" : "blockUser",
-    "click .hide_post" : "hidePost",
+    "click .hide_post" : "hidePost"
   },
 
   tooltipSelector : ".label",
 
   initialize : function() {
-    this.model.interactions.on('change', this.render, this);
+    this.model.interactions.on("change", this.render, this);
     this.initViews && this.initViews(); // I don't know why this was failing with $.noop... :(
   },
 
@@ -47,7 +47,7 @@ app.views.Feedback = app.views.Base.extend({
 
   blockUser: function(evt) {
     if(evt) { evt.preventDefault(); }
-    if(!confirm(Diaspora.I18n.t('ignore_user'))) { return; }
+    if(!confirm(Diaspora.I18n.t("ignore_user"))) { return; }
 
     this.model.blockAuthor()
       .done(function() {
@@ -55,16 +55,13 @@ app.views.Feedback = app.views.Base.extend({
         document.location.href = "/stream";
       })
       .fail(function() {
-        Diaspora.page.flashMessages.render({
-          success: false,
-          notice: Diaspora.I18n.t('hide_post_failed')
-        });
+        app.flashMessages.error(Diaspora.I18n.t("hide_post_failed"));
       });
   },
 
   hidePost : function(evt) {
     if(evt) { evt.preventDefault(); }
-    if(!confirm(Diaspora.I18n.t('hide_post'))) { return; }
+    if(!confirm(Diaspora.I18n.t("hide_post"))) { return; }
 
     $.ajax({
       url : "/share_visibilities/42",
@@ -77,11 +74,8 @@ app.views.Feedback = app.views.Base.extend({
         document.location.href = "/stream";
       })
       .fail(function() {
-        Diaspora.page.flashMessages.render({
-          success: false,
-          notice: Diaspora.I18n.t('ignore_post_failed')
-        });
+        app.flashMessages.error(Diaspora.I18n.t("ignore_post_failed"));
       });
-  },
+  }
 });
 // @license-end
diff --git a/app/assets/javascripts/app/views/flash_messages_view.js b/app/assets/javascripts/app/views/flash_messages_view.js
new file mode 100644
index 0000000000000000000000000000000000000000..cb5b214b23637c19620252568bcd78fe970d6936
--- /dev/null
+++ b/app/assets/javascripts/app/views/flash_messages_view.js
@@ -0,0 +1,20 @@
+app.views.FlashMessages = app.views.Base.extend({
+  templateName: "flash_messages",
+
+  _flash: function(message, error){
+    this.presenter = {
+      message: message,
+      alertLevel: error ? "alert-danger" : "alert-success"
+    };
+
+    this.renderTemplate();
+  },
+
+  success: function(message){
+    this._flash(message, false);
+  },
+
+  error: function(message){
+    this._flash(message, true);
+  }
+});
diff --git a/app/assets/javascripts/app/views/pod_entry_view.js b/app/assets/javascripts/app/views/pod_entry_view.js
index 8e08c9771301618f4b90405f0f419555a96d8552..c8c402fb88b3d0235a64c4756134c781edc97acf 100644
--- a/app/assets/javascripts/app/views/pod_entry_view.js
+++ b/app/assets/javascripts/app/views/pod_entry_view.js
@@ -52,22 +52,15 @@ app.views.PodEntry = app.views.Base.extend({
   },
 
   recheckPod: function() {
-    var self  = this,
-        flash = new Diaspora.Widgets.FlashMessages();
+    var self  = this;
     this.$el.addClass("checking");
 
     this.model.recheck()
       .done(function(){
-        flash.render({
-          success: true,
-          notice: Diaspora.I18n.t("admin.pods.recheck.success")
-        });
+        app.flashMessages.success(Diaspora.I18n.t("admin.pods.recheck.success"));
       })
       .fail(function(){
-        flash.render({
-          success: false,
-          notice: Diaspora.I18n.t("admin.pods.recheck.failure")
-        });
+        app.flashMessages.error(Diaspora.I18n.t("admin.pods.recheck.failure"));
       })
       .always(function(){
         self.$el
diff --git a/app/assets/javascripts/app/views/publisher_view.js b/app/assets/javascripts/app/views/publisher_view.js
index 4e128a5726975157e2557c3e72c9afd716aea91e..8115674e3ff9bc8dfc3a27e269ce1a77b0fc118f 100644
--- a/app/assets/javascripts/app/views/publisher_view.js
+++ b/app/assets/javascripts/app/views/publisher_view.js
@@ -215,7 +215,7 @@ app.views.Publisher = Backbone.View.extend({
           app.publisher.trigger("publisher:error");
         }
         self.setInputEnabled(true);
-        Diaspora.page.flashMessages.render({ "success":false, "notice":resp.responseText });
+        app.flashMessages.error(resp.responseText);
         self.setButtonsEnabled(true);
         self.setInputEnabled(true);
       }
diff --git a/app/assets/javascripts/app/views/single-post-viewer/single_post_moderation.js b/app/assets/javascripts/app/views/single-post-viewer/single_post_moderation.js
index 8604d1adc91141cc518294bd61736a8fa1a53556..823783da3d59ea965fc98ebb774cbf0a506cf90c 100644
--- a/app/assets/javascripts/app/views/single-post-viewer/single_post_moderation.js
+++ b/app/assets/javascripts/app/views/single-post-viewer/single_post_moderation.js
@@ -1,7 +1,7 @@
 app.views.SinglePostModeration = app.views.Feedback.extend({
   templateName: "single-post-viewer/single-post-moderation",
 
-  className: 'control-icons',
+  className: "control-icons",
 
   events: function() {
     return _.defaults({
@@ -19,7 +19,7 @@ app.views.SinglePostModeration = app.views.Feedback.extend({
 
   renderPluginWidgets : function() {
     app.views.Base.prototype.renderPluginWidgets.apply(this);
-    this.$('a').tooltip({placement: 'bottom'});
+    this.$("a").tooltip({placement: "bottom"});
   },
 
   authorIsCurrentUser: function() {
@@ -28,7 +28,7 @@ app.views.SinglePostModeration = app.views.Feedback.extend({
 
   destroyModel: function(evt) {
     if(evt) { evt.preventDefault(); }
-    var url = this.model.urlRoot + '/' + this.model.id;
+    var url = this.model.urlRoot + "/" + this.model.id;
 
     if (confirm(Diaspora.I18n.t("remove_post"))) {
       this.model.destroy({ url: url })
@@ -37,11 +37,7 @@ app.views.SinglePostModeration = app.views.Feedback.extend({
           document.location.href = "/stream";
         })
         .fail(function() {
-          var flash = new Diaspora.Widgets.FlashMessages();
-          flash.render({
-            success: false,
-            notice: Diaspora.I18n.t('failed_to_remove')
-          });
+          app.flashMessages.error(Diaspora.I18n.t("failed_to_remove"));
         });
     }
   },
diff --git a/app/assets/javascripts/app/views/stream_post_views.js b/app/assets/javascripts/app/views/stream_post_views.js
index 81a495411ea60e8f89ddb440a3d205461f12464f..ccf893e63612ab8582bc226636cbbbd432a325a1 100644
--- a/app/assets/javascripts/app/views/stream_post_views.js
+++ b/app/assets/javascripts/app/views/stream_post_views.js
@@ -39,10 +39,10 @@ app.views.StreamPost = app.views.Post.extend({
                      ".permalink"].join(", "),
 
   initialize : function(){
-    var personId = this.model.get('author').id;
-    app.events.on('person:block:'+personId, this.remove, this);
+    var personId = this.model.get("author").id;
+    app.events.on("person:block:"+personId, this.remove, this);
 
-    this.model.on('remove', this.remove, this);
+    this.model.on("remove", this.remove, this);
     //subviews
     this.commentStreamView = new app.views.CommentStream({model : this.model});
     this.oEmbedView = new app.views.OEmbed({model : this.model});
@@ -85,14 +85,11 @@ app.views.StreamPost = app.views.Post.extend({
 
   blockUser: function(evt){
     if(evt) { evt.preventDefault(); }
-    if(!confirm(Diaspora.I18n.t('ignore_user'))) { return }
+    if(!confirm(Diaspora.I18n.t("ignore_user"))) { return }
 
     this.model.blockAuthor()
       .fail(function() {
-        Diaspora.page.flashMessages.render({
-          success: false,
-          notice: Diaspora.I18n.t('ignore_failed')
-        });
+        app.flashMessages.error(Diaspora.I18n.t("ignore_failed"));
       });
   },
 
@@ -104,7 +101,7 @@ app.views.StreamPost = app.views.Post.extend({
 
   hidePost : function(evt) {
     if(evt) { evt.preventDefault(); }
-    if(!confirm(Diaspora.I18n.t('confirm_dialog'))) { return }
+    if(!confirm(Diaspora.I18n.t("confirm_dialog"))) { return }
 
     var self = this;
     $.ajax({
@@ -117,10 +114,7 @@ app.views.StreamPost = app.views.Post.extend({
         self.remove();
       })
       .fail(function() {
-        Diaspora.page.flashMessages.render({
-          success: false,
-          notice: Diaspora.I18n.t('hide_post_failed')
-        });
+        app.flashMessages.error(Diaspora.I18n.t("hide_post_failed"));
       });
   },
 
diff --git a/app/assets/javascripts/diaspora.js b/app/assets/javascripts/diaspora.js
index 8aacf6e36e1fb008b5d266a044c04fda79ef788d..b05b2860109b1a2c141158ae2b313ef94675e182 100644
--- a/app/assets/javascripts/diaspora.js
+++ b/app/assets/javascripts/diaspora.js
@@ -70,7 +70,6 @@
     $.extend(this, {
       directionDetector: this.instantiate("DirectionDetector"),
       events: function() { return Diaspora.page.eventsContainer.data("events"); },
-      flashMessages: this.instantiate("FlashMessages"),
       header: this.instantiate("Header", body.find("header")),
       timeAgo: this.instantiate("TimeAgo")
     });
diff --git a/app/assets/javascripts/pages/users-getting-started.js b/app/assets/javascripts/pages/users-getting-started.js
index 2fed55655a8c6af6c3649b5ba6ba4f672983dd6c..fb6184ba6547c092be4305ab3f44fe25de267ae7 100644
--- a/app/assets/javascripts/pages/users-getting-started.js
+++ b/app/assets/javascripts/pages/users-getting-started.js
@@ -18,7 +18,7 @@ Diaspora.Pages.UsersGettingStarted = function() {
 
       /* flash message prompt */
       var message = Diaspora.I18n.t("getting_started.hey", {'name': $("#profile_first_name").val()});
-      Diaspora.page.flashMessages.render({success: true, notice: message});
+      app.flashMessages.success(message);
     });
 
     $("#profile_first_name").bind("change", function(){
@@ -45,7 +45,7 @@ Diaspora.Pages.UsersGettingStarted = function() {
         confirmation = confirm(confirmMessage);
       }
 
-      Diaspora.page.flashMessages.render({success: true, notice: message});
+      app.flashMessages.success(message);
       return confirmation;
     });
 
@@ -66,7 +66,7 @@ Diaspora.Pages.UsersGettingStarted = function() {
       startText: "",
       emptyText: "no_results",
       selectionAdded: function(elem){tagFollowings.create({"name":$(elem[0]).text().substring(2)})},
-      selectionRemoved: function(elem){ 
+      selectionRemoved: function(elem){
         tagFollowings.where({"name":$(elem[0]).text().substring(2)})[0].destroy();
         elem.remove();
       }
diff --git a/app/assets/javascripts/widgets/flash-messages.js b/app/assets/javascripts/widgets/flash-messages.js
deleted file mode 100644
index 4cb0c9382b6b218e4646c126abff648c1f9dcf09..0000000000000000000000000000000000000000
--- a/app/assets/javascripts/widgets/flash-messages.js
+++ /dev/null
@@ -1,38 +0,0 @@
-// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
-
-(function() {
-  var FlashMessages = function() {
-    var self = this;
-
-    this.subscribe("widget/ready", function() {
-      self.animateMessages();
-    });
-
-    this.animateMessages = function() {
-      self.flashMessages().addClass("expose").delay(8000).fadeTo(200, 0.5);
-    };
-
-    this.render = function(result) {
-      self.flashMessages().removeClass("expose").remove();
-
-      $("<div/>", {
-        id: result.success ? "flash_notice" : "flash_error"
-      })
-      .html($("<div/>", {
-        'class': "message"
-        })
-        .text(result.notice))
-      .prependTo(document.body);
-
-
-      self.animateMessages();
-    };
-
-    this.flashMessages = function() {
-      return $("#flash_notice, #flash_error, #flash_alert");
-    };
-  };
-
-  Diaspora.Widgets.FlashMessages = FlashMessages;
-})();
-// @license-end
diff --git a/app/assets/stylesheets/_flash_messages.scss b/app/assets/stylesheets/_flash_messages.scss
index 851d9eae88f7a12a07778bd412beddfaf09f5a72..99d494a7a787b262759a580ba2b08f4d34f187dc 100644
--- a/app/assets/stylesheets/_flash_messages.scss
+++ b/app/assets/stylesheets/_flash_messages.scss
@@ -1,50 +1,22 @@
-#flash_notice,
-#flash_alert,
-#flash_error {
-  position : fixed;
+#flash-body {
+  left: 0;
+  position: fixed;
+  text-align: center;
+  top: -100px;
   z-index: 999;
-  top : -100px;
-  left : 0;
-  width : 100%;
-
-  text-align : center;
-  color: $text-dark-grey;
-
-  &.expose {
-    @include animation(expose, 10s)
-  }
-
-  .message {
-    box-shadow: 0 1px 4px rgba(0,0,0,0.8);
-
-    display : inline-block;
-    padding: 10px 12px;
-    min-width: 400px;
-    max-width: 800px;
-
-    color : #fff;
-    background-color : rgba(0,0,0,0.8);
-    border : 1px solid rgba(255,255,255,0.7);
-    border-radius: 6px;
+  width: 100%;
+  &.expose {  @include animation(expose, 10s) }
 
+  #flash-message {
+    border-radius: 0;
+    box-shadow: $card-shadow;
+    display: inline-block;
     font-weight: bold;
-    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
-    font-size: 13px;
-  }
-}
-
-#flash_notice {
-  .message {
-    color: $text-dark-grey;
-    background-color: #F4F899;
-    border-color: darken(#F4F899, 40%);
-  }
-}
-
-#flash_error,
-#flash_alert {
-  .message {
-    background-color: #CA410B;
-    border-color: darken(#CA410B, 10%);
+    max-width: 800px;
+    min-width: 500px;
+    padding: 10px 12px;
+    &.alert-danger { border: 1px solid darken($state-danger-bg, 10%); }
+    &.alert-succes { border: 1px solid darken($state-success-bg, 10%); }
+    &.alert-warning { border: 1px solid darken($state-warning-bg, 10%); }
   }
 }
diff --git a/app/assets/stylesheets/mobile/mobile.scss b/app/assets/stylesheets/mobile/mobile.scss
index e5da0ea7129eb51322fde957e071982747be93cf..4ad15e0e3e1a46cc8c736613d1b6db988b69dad7 100644
--- a/app/assets/stylesheets/mobile/mobile.scss
+++ b/app/assets/stylesheets/mobile/mobile.scss
@@ -35,10 +35,6 @@ h3 {  margin-top: 0; }
 .clear { clear: both; }
 #main { padding: 56px 10px 0 10px; }
 
-.message {
-  padding-left: 2px;
-}
-
 .avatar {
   border-radius: 4px;
 }
diff --git a/app/assets/templates/flash_messages_tpl.jst.hbs b/app/assets/templates/flash_messages_tpl.jst.hbs
new file mode 100644
index 0000000000000000000000000000000000000000..efe61b41cd74e638fe8176e490b17ece3cefcf1a
--- /dev/null
+++ b/app/assets/templates/flash_messages_tpl.jst.hbs
@@ -0,0 +1,5 @@
+<div id="flash-body" class="expose">
+  <div id="flash-message" class="alert {{ alertLevel }}">
+    {{ message }}
+  </div>
+</div>
diff --git a/app/helpers/layout_helper.rb b/app/helpers/layout_helper.rb
index cf87f6c5f728e571a46d68caf2162e363c30d586..84eb4c0694f23c9e23951c12a4608fa47e3b2bd5 100644
--- a/app/helpers/layout_helper.rb
+++ b/app/helpers/layout_helper.rb
@@ -67,8 +67,15 @@ module LayoutHelper
 
   def flash_messages
     flash.map do |name, msg|
-      content_tag(:div, :id => "flash_#{name}") do
-        content_tag(:div, msg, :class => 'message')
+      klass = if name == "alert"
+                "warning"
+              elsif name == "error"
+                "danger"
+              else
+                "success"
+              end
+      content_tag(:div, msg, id: "flash-body", class: "expose") do
+        content_tag(:div, msg, id: "flash-message", class: "message alert alert-#{klass}")
       end
     end.join(' ').html_safe
   end
diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb
index f76d793a126615c0ae75fa8bf9f21f17070e8ba4..74f5695e73c585e5e94337953cf8d5e25f769467 100644
--- a/app/helpers/sessions_helper.rb
+++ b/app/helpers/sessions_helper.rb
@@ -1,6 +1,6 @@
 module SessionsHelper
   def prefilled_username
-    uri = Addressable::URI.parse(session['user_return_to'])
+    uri = Addressable::URI.parse(session["user_return_to"])
     if uri && uri.query_values
       uri.query_values["username"]
     else
@@ -9,10 +9,14 @@ module SessionsHelper
   end
 
   def display_registration_link?
-    AppConfig.settings.enable_registrations? && devise_mapping.registerable? && controller_name != 'registrations'
+    AppConfig.settings.enable_registrations? && devise_mapping.registerable? && controller_name != "registrations"
   end
 
   def display_password_reset_link?
-    devise_mapping.recoverable? && controller_name != 'passwords'
+    devise_mapping.recoverable? && controller_name != "passwords"
+  end
+
+  def flash_class(name)
+    {notice: "success", alert: "warning", error: "danger"}[name.to_sym]
   end
 end
diff --git a/app/views/conversations/create.js.erb b/app/views/conversations/create.js.erb
index 95ffa52cabc07e967edbb1dc754fbb8b8b3f595d..362ccfa827be60b976027dc054c08a9a6fe07eda 100644
--- a/app/views/conversations/create.js.erb
+++ b/app/views/conversations/create.js.erb
@@ -2,7 +2,7 @@ var response = <%= raw @response.to_json %>;
 <% if session[:mobile_view] %>
   window.location.href = "<%= conversations_path(conversation_id: @conversation.id) %>";
 <% else %>
-  Diaspora.page.flashMessages.render({ 'success':response.success, 'notice':response.message });
+  app.flashMessages._flash(response.message, response.success);
   if(response.success){
     $("#new_conversation").removeClass('form_do_not_clear').clearForm();
     window.location.href = "<%= conversations_path(conversation_id: @conversation.id) %>";
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index d1ff942432dda70766e21819501e05a8b0bf551d..67066ccd13787b6a01d07f76c6136c2d42eb45a4 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -47,8 +47,6 @@
     = include_gon(camel_case:  true)
 
   %body{ class:  "page-#{controller_name} action-#{action_name}" }
-    = flash_messages
-
     = yield :before_content
 
     = content_for?(:content) ? yield(:content) : yield
@@ -69,3 +67,5 @@
         .entypo-cross
       %a.play-pause
       %ol.indicator
+
+    #flash-container= flash_messages
diff --git a/app/views/photos/_new_profile_photo.haml b/app/views/photos/_new_profile_photo.haml
index f89d5ac383019f691b864da9cb9093da55da05a5..70b0d4c37c807bbf4da0b1ae16e60e127a6d6ccf 100644
--- a/app/views/photos/_new_profile_photo.haml
+++ b/app/views/photos/_new_profile_photo.haml
@@ -38,7 +38,7 @@
 
           /* flash message prompt */
           var message = Diaspora.I18n.t("photo_uploader.looking_good");
-          Diaspora.page.flashMessages.render({success: true, notice: message});
+          app.flashMessages.success(message);
 
           var id = responseJSON.data.photo.id;
           var url = responseJSON.data.photo.unprocessed_image.url;
diff --git a/app/views/sessions/new.mobile.haml b/app/views/sessions/new.mobile.haml
index 5f6c1fafa3f46190a0448569fd49541a5d4bf0c5..0ae8bba47fc485a6581a953c83437cf3291f7c34 100644
--- a/app/views/sessions/new.mobile.haml
+++ b/app/views/sessions/new.mobile.haml
@@ -9,10 +9,8 @@
 
   #main_stream.stream
     - flash.each do |name, msg|
-      %p{class: "login_#{name}"}
-        = msg
-      #flash_alert.expose
-        #session.message
+      .expose#flash-container
+        #flash-message{class: "message alert alert-#{flash_class name}"}
           = msg
 
     #login_form
diff --git a/app/views/tags/update.js.erb b/app/views/tags/update.js.erb
index cf75adc4c8959bbbea25c7ec0fba6ebab33dbc11..16b65b62c6b8169a92dc6e4378abdf75be6d225e 100644
--- a/app/views/tags/update.js.erb
+++ b/app/views/tags/update.js.erb
@@ -1,3 +1,3 @@
 var tagName = "<%= escape_javascript(@tag.name) %>"
 $("#followed_tags_listing").find("#tag-following-"+tagName).slideUp(100);
-Diaspora.page.flashMessages.render({success: true, notice: Diaspora.I18n.t("tags.wasnt_that_interesting", {tagName: tagName})});
+app.flashMessages.success(Diaspora.I18n.t("tags.wasnt_that_interesting", {tagName: tagName}));
diff --git a/features/support/application_cuke_helpers.rb b/features/support/application_cuke_helpers.rb
index f45054494030e166d793c7037bfa3ed23614f93c..95e100120e1a3c30280374856473f747c74e6a13 100644
--- a/features/support/application_cuke_helpers.rb
+++ b/features/support/application_cuke_helpers.rb
@@ -1,14 +1,14 @@
 module ApplicationCukeHelpers
   def flash_message_success?
-    flash_message(selector: "notice").visible?
+    flash_message(selector: "success").visible?
   end
 
   def flash_message_failure?
-    flash_message(selector: "error").visible?
+    flash_message(selector: "danger").visible?
   end
 
   def flash_message_alert?
-    flash_message(selector: "alert").visible?
+    flash_message(selector: "warning").visible?
   end
 
   def flash_message_containing?(text)
@@ -17,8 +17,8 @@ module ApplicationCukeHelpers
 
   def flash_message(opts={})
     selector = opts.delete(:selector)
-    selector &&= "#flash_#{selector}"
-    find(selector || '.message', {match: :first}.merge(opts))
+    selector &&= ".alert-#{selector}"
+    find(selector || "#flash-message", {match: :first}.merge(opts))
   end
 
   def confirm_form_validation_error(element)
@@ -27,8 +27,8 @@ module ApplicationCukeHelpers
   end
 
   def check_fields_validation_error(field_list)
-    field_list.split(',').each do |f|
-      confirm_form_validation_error('input#'+f.strip)
+    field_list.split(",").each do |f|
+      confirm_form_validation_error("input##{f.strip}")
     end
   end
 
diff --git a/spec/javascripts/app/views/aspect_create_view_spec.js b/spec/javascripts/app/views/aspect_create_view_spec.js
index 1961cff0864029a6768c7f1618fcf4dbc5393280..cef1acf3ff59d3b2c1f93e349fae65ea96e80c6c 100644
--- a/spec/javascripts/app/views/aspect_create_view_spec.js
+++ b/spec/javascripts/app/views/aspect_create_view_spec.js
@@ -62,6 +62,8 @@ describe("app.views.AspectCreate", function() {
     describe("#createAspect", function() {
       beforeEach(function() {
         this.view.render();
+        this.view.$el.append($("<div id='flash-container'/>"));
+        app.flashMessages = new app.views.FlashMessages({ el: this.view.$("#flash-container") });
       });
 
       it("should send the correct name to the server", function() {
@@ -115,7 +117,7 @@ describe("app.views.AspectCreate", function() {
         it("should display a flash message", function() {
           this.view.createAspect();
           jasmine.Ajax.requests.mostRecent().respondWith(this.response);
-          expect($("[id^=\"flash\"]")).toBeSuccessFlashMessage(
+          expect(this.view.$("#flash-message")).toBeSuccessFlashMessage(
             Diaspora.I18n.t("aspects.create.success", {name: "new name"})
           );
         });
@@ -138,7 +140,7 @@ describe("app.views.AspectCreate", function() {
         it("should display a flash message", function() {
           this.view.createAspect();
           jasmine.Ajax.requests.mostRecent().respondWith(this.response);
-          expect($("[id^=\"flash\"]")).toBeErrorFlashMessage(
+          expect(this.view.$("#flash-message")).toBeErrorFlashMessage(
             Diaspora.I18n.t("aspects.create.failure")
           );
         });
diff --git a/spec/javascripts/app/views/aspect_membership_view_spec.js b/spec/javascripts/app/views/aspect_membership_view_spec.js
index 7ff709ead9710f783803c0fa6b6fce3ee5d75d9b..9e8d2ed0ac27c2a77717fa5f8234ce84e35f6cbe 100644
--- a/spec/javascripts/app/views/aspect_membership_view_spec.js
+++ b/spec/javascripts/app/views/aspect_membership_view_spec.js
@@ -6,6 +6,8 @@ describe("app.views.AspectMembership", function(){
     // mock a dummy aspect dropdown
     spec.loadFixture("aspect_membership_dropdown");
     this.view = new app.views.AspectMembership({el: $('.aspect_membership_dropdown')});
+    this.view.$el.append($("<div id='flash-container'/>"));
+    app.flashMessages = new app.views.FlashMessages({ el: this.view.$("#flash-container") });
     this.personId = $(".dropdown-menu").data("person_id");
     this.personName = $(".dropdown-menu").data("person-short-name");
     Diaspora.I18n.load({
@@ -36,7 +38,7 @@ describe("app.views.AspectMembership", function(){
       this.newAspect.trigger('click');
       jasmine.Ajax.requests.mostRecent().respondWith(success);
 
-      expect($('[id^="flash"]')).toBeSuccessFlashMessage(
+      expect(this.view.$("#flash-message")).toBeSuccessFlashMessage(
         Diaspora.I18n.t("aspect_dropdown.started_sharing_with", {name: this.personName})
       );
     });
@@ -56,7 +58,7 @@ describe("app.views.AspectMembership", function(){
       this.newAspect.trigger('click');
       jasmine.Ajax.requests.mostRecent().respondWith(resp_fail);
 
-      expect($('[id^="flash"]')).toBeErrorFlashMessage(
+      expect(this.view.$("#flash-message")).toBeErrorFlashMessage(
         Diaspora.I18n.t("aspect_dropdown.error", {name: this.personName})
       );
     });
@@ -80,7 +82,7 @@ describe("app.views.AspectMembership", function(){
       this.oldAspect.trigger('click');
       jasmine.Ajax.requests.mostRecent().respondWith(success);
 
-      expect($('[id^="flash"]')).toBeSuccessFlashMessage(
+      expect(this.view.$("#flash-message")).toBeSuccessFlashMessage(
         Diaspora.I18n.t("aspect_dropdown.stopped_sharing_with", {name: this.personName})
       );
     });
@@ -100,7 +102,7 @@ describe("app.views.AspectMembership", function(){
       this.oldAspect.trigger('click');
       jasmine.Ajax.requests.mostRecent().respondWith(resp_fail);
 
-      expect($('[id^="flash"]')).toBeErrorFlashMessage(
+      expect(this.view.$("#flash-message")).toBeErrorFlashMessage(
         Diaspora.I18n.t("aspect_dropdown.error_remove", {name: this.personName})
       );
     });
diff --git a/spec/javascripts/app/views/comment_stream_view_spec.js b/spec/javascripts/app/views/comment_stream_view_spec.js
index dfb20219c9ba27698589dee58185a7808a67c435..06e2e4ae52277af6e7446e7bbc25d9ad386bee7d 100644
--- a/spec/javascripts/app/views/comment_stream_view_spec.js
+++ b/spec/javascripts/app/views/comment_stream_view_spec.js
@@ -32,6 +32,8 @@ describe("app.views.CommentStream", function(){
   describe("createComment", function() {
     beforeEach(function() {
       this.view.render();
+      this.view.$el.append($("<div id='flash-container'/>"));
+      app.flashMessages = new app.views.FlashMessages({ el: this.view.$("#flash-container") });
       this.view.expandComments();
     });
 
@@ -59,7 +61,7 @@ describe("app.views.CommentStream", function(){
         this.request.respondWith({status: 500});
 
         expect(this.view.$(".comment-content p").text()).not.toEqual("a new comment");
-        expect($('*[id^="flash"]')).toBeErrorFlashMessage("posting failed!");
+        expect(this.view.$("#flash-message")).toBeErrorFlashMessage("posting failed!");
       });
     });
 
diff --git a/spec/javascripts/app/views/contact_view_spec.js b/spec/javascripts/app/views/contact_view_spec.js
index 70988205810f85a50e0ffa8cc6ee18c6caf58e54..a3390c305a1fb4ac9dbb402f5e9486a3ce272c86 100644
--- a/spec/javascripts/app/views/contact_view_spec.js
+++ b/spec/javascripts/app/views/contact_view_spec.js
@@ -5,7 +5,7 @@ describe("app.views.Contact", function(){
 
     this.model = new app.models.Contact({
       person_id: 42,
-      person: { id: 42, name: 'alice' },
+      person: { id: 42, name: "alice" },
       aspect_memberships: [{id: 23, aspect: this.aspect1}]
     });
     this.view = new app.views.Contact({ model: this.model });
@@ -24,32 +24,34 @@ describe("app.views.Contact", function(){
       app.aspect = this.aspect1;
       expect(this.view.presenter()).toEqual(jasmine.objectContaining({
         person_id: 42,
-        person: jasmine.objectContaining({id: 42, name: 'alice'}),
+        person: jasmine.objectContaining({id: 42, name: "alice"}),
         in_aspect: 'in_aspect'
       }));
     });
   });
 
-  context('add contact to aspect', function() {
+  context("add contact to aspect", function() {
     beforeEach(function() {
       app.aspect = this.aspect2;
       this.view.render();
-      this.button = this.view.$el.find('.contact_add-to-aspect');
-      this.contact = this.view.$el.find('.stream_element.contact');
+      this.view.$el.append($("<div id='flash-container'/>"));
+      app.flashMessages = new app.views.FlashMessages({ el: this.view.$("#flash-container") });
+      this.button = this.view.$el.find(".contact_add-to-aspect");
+      this.contact = this.view.$el.find(".stream_element.contact");
       this.aspectMembership = {id: 42, aspect: app.aspect.toJSON()};
       this.response = JSON.stringify(this.aspectMembership);
     });
 
-    it('sends a correct ajax request', function() {
-      this.button.trigger('click');
+    it("sends a correct ajax request", function() {
+      this.button.trigger("click");
       var obj = $.parseJSON(jasmine.Ajax.requests.mostRecent().params);
       expect(obj.person_id).toBe(this.model.get('person_id'));
       expect(obj.aspect_id).toBe(app.aspect.get('id'));
     });
 
-    it('adds a aspect_membership to the contact', function() {
+    it("adds a aspect_membership to the contact", function() {
       expect(this.model.aspectMemberships.length).toBe(1);
-      $('.contact_add-to-aspect',this.contact).trigger('click');
+      $(".contact_add-to-aspect",this.contact).trigger("click");
       jasmine.Ajax.requests.mostRecent().respondWith({
         status: 200, // success
         responseText: this.response
@@ -70,9 +72,9 @@ describe("app.views.Contact", function(){
       });
     });
 
-    it('calls render', function() {
-      spyOn(this.view, 'render');
-      $('.contact_add-to-aspect',this.contact).trigger('click');
+    it("calls render", function() {
+      spyOn(this.view, "render");
+      $(".contact_add-to-aspect",this.contact).trigger("click");
       jasmine.Ajax.requests.mostRecent().respondWith({
         status: 200, // success
         responseText: this.response
@@ -81,40 +83,39 @@ describe("app.views.Contact", function(){
     });
 
 
-    it('displays a flash message on errors', function(){
-      $('.contact_add-to-aspect',this.contact).trigger('click');
+    it("displays a flash message on errors", function(){
+      $(".contact_add-to-aspect",this.contact).trigger("click");
       jasmine.Ajax.requests.mostRecent().respondWith({
-        status: 400, // fail
+        status: 400 // fail
       });
-      expect($('[id^="flash"]')).toBeErrorFlashMessage(
-        Diaspora.I18n.t(
-          'contacts.error_add',
-          {name: this.model.get('person').name}
-        )
+      expect(this.view.$("#flash-message")).toBeErrorFlashMessage(
+        Diaspora.I18n.t( "contacts.error_add", {name: this.model.get("person").name} )
       );
     });
   });
 
-  context('remove contact from aspect', function() {
+  context("remove contact from aspect", function() {
     beforeEach(function() {
       app.aspect = this.aspect1;
       this.view.render();
-      this.button = this.view.$el.find('.contact_remove-from-aspect');
-      this.contact = this.view.$el.find('.stream_element.contact');
+      this.view.$el.append($("<div id='flash-container'/>"));
+      app.flashMessages = new app.views.FlashMessages({ el: this.view.$("#flash-container") });
+      this.button = this.view.$el.find(".contact_remove-from-aspect");
+      this.contact = this.view.$el.find(".stream_element.contact");
       this.aspectMembership = this.model.aspectMemberships.first().toJSON();
       this.response = JSON.stringify(this.aspectMembership);
     });
 
-    it('sends a correct ajax request', function() {
-      $('.contact_remove-from-aspect',this.contact).trigger('click');
+    it("sends a correct ajax request", function() {
+      $(".contact_remove-from-aspect",this.contact).trigger("click");
       expect(jasmine.Ajax.requests.mostRecent().url).toBe(
         "/aspect_memberships/"+this.aspectMembership.id
       );
     });
 
-    it('removes the aspect_membership from the contact', function() {
+    it("removes the aspect_membership from the contact", function() {
       expect(this.model.aspectMemberships.length).toBe(1);
-      $('.contact_remove-from-aspect',this.contact).trigger('click');
+      $(".contact_remove-from-aspect",this.contact).trigger("click");
       jasmine.Ajax.requests.mostRecent().respondWith({
         status: 200, // success
         responseText: this.response
@@ -135,9 +136,9 @@ describe("app.views.Contact", function(){
       });
     });
 
-    it('calls render', function() {
-      spyOn(this.view, 'render');
-      $('.contact_remove-from-aspect',this.contact).trigger('click');
+    it("calls render", function() {
+      spyOn(this.view, "render");
+      $(".contact_remove-from-aspect",this.contact).trigger("click");
       jasmine.Ajax.requests.mostRecent().respondWith({
         status: 200, // success
         responseText: this.response,
@@ -145,16 +146,13 @@ describe("app.views.Contact", function(){
       expect(this.view.render).toHaveBeenCalled();
     });
 
-    it('displays a flash message on errors', function(){
-      $('.contact_remove-from-aspect',this.contact).trigger('click');
+    it("displays a flash message on errors", function(){
+      $(".contact_remove-from-aspect",this.contact).trigger("click");
       jasmine.Ajax.requests.mostRecent().respondWith({
-        status: 400, // fail
+        status: 400 // fail
       });
-      expect($('[id^="flash"]')).toBeErrorFlashMessage(
-        Diaspora.I18n.t(
-          'contacts.error_remove',
-          {name: this.model.get('person').name}
-        )
+      expect(this.view.$("#flash-message")).toBeErrorFlashMessage(
+        Diaspora.I18n.t( "contacts.error_remove", {name: this.model.get("person").name})
       );
     });
   });
diff --git a/spec/javascripts/app/views/conversations_view_spec.js b/spec/javascripts/app/views/conversations_view_spec.js
index a33b9f6210e367f620834d61bb11a8d8f5a121ce..d48b880479574481e1a7cf3d0364ee60e1ed445e 100644
--- a/spec/javascripts/app/views/conversations_view_spec.js
+++ b/spec/javascripts/app/views/conversations_view_spec.js
@@ -4,8 +4,8 @@ describe("app.views.Conversations", function(){
       beforeEach(function() {
         spec.loadFixture("conversations_unread");
         // select second conversation that is still unread
-        $(".conversation-wrapper > .conversation.selected").removeClass("selected")
-        $(".conversation-wrapper > .conversation.unread").addClass("selected")
+        $(".conversation-wrapper > .conversation.selected").removeClass("selected");
+        $(".conversation-wrapper > .conversation.unread").addClass("selected");
       });
 
       it("removes the unread class from the conversation", function() {
diff --git a/spec/javascripts/app/views/flash_messages_view-spec.js b/spec/javascripts/app/views/flash_messages_view-spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..4c5c31b9a80d54304fcea156d0e51b48d9bb3d6d
--- /dev/null
+++ b/spec/javascripts/app/views/flash_messages_view-spec.js
@@ -0,0 +1,33 @@
+describe("app.views.FlashMessages", function(){
+  var flashMessages = new app.views.FlashMessages();
+
+  describe("flash", function(){
+    it("call _flash with correct parameters", function() {
+      spyOn(flashMessages, "_flash");
+      flashMessages.success("success!");
+      expect(flashMessages._flash).toHaveBeenCalledWith("success!", false);
+      flashMessages.error("error!");
+      expect(flashMessages._flash).toHaveBeenCalledWith("error!", true);
+    });
+  });
+
+  describe("render", function(){
+    beforeEach(function(){
+      spec.content().html("<div id='flash-container'/>");
+      flashMessages = new app.views.FlashMessages({ el: $("#flash-container") });
+    });
+
+    it("renders a success message", function(){
+      flashMessages.success("success!");
+      expect(flashMessages.$("#flash-body")).toHaveClass("expose");
+      expect($("#flash-message")).toHaveClass("alert-success");
+      expect($("#flash-message").text().trim()).toBe("success!");
+    });
+    it("renders an error message", function(){
+      flashMessages.error("error!");
+      expect(flashMessages.$("#flash-body")).toHaveClass("expose");
+      expect($("#flash-message")).toHaveClass("alert-danger");
+      expect($("#flash-message").text().trim()).toBe("error!");
+    });
+  });
+});
diff --git a/spec/javascripts/app/views/pod_entry_view_spec.js b/spec/javascripts/app/views/pod_entry_view_spec.js
index 81777b6af3e9cf731ecec2620aae3318c806ff26..592ea85306df69c2e41fb9be1c15fd05667ee279 100644
--- a/spec/javascripts/app/views/pod_entry_view_spec.js
+++ b/spec/javascripts/app/views/pod_entry_view_spec.js
@@ -57,6 +57,11 @@ describe("app.views.PodEntry", function() {
   describe("recheckPod", function() {
     var ajaxSuccess = { status: 200, responseText: "{}" };
     var ajaxFail = { status: 400 };
+    beforeEach(function(){
+      this.view.render();
+      this.view.$el.append($("<div id='flash-container'/>"));
+      app.flashMessages = new app.views.FlashMessages({ el: this.view.$("#flash-container") });
+    });
 
     it("calls .recheck() on the model", function() {
       spyOn(this.pod, "recheck").and.returnValue($.Deferred());
@@ -67,13 +72,13 @@ describe("app.views.PodEntry", function() {
     it("renders a success flash message", function() {
       this.view.recheckPod();
       jasmine.Ajax.requests.mostRecent().respondWith(ajaxSuccess);
-      expect($("[id^=\"flash\"]")).toBeSuccessFlashMessage();
+      expect(this.view.$("#flash-message")).toBeSuccessFlashMessage();
     });
 
     it("renders an error flash message", function() {
       this.view.recheckPod();
       jasmine.Ajax.requests.mostRecent().respondWith(ajaxFail);
-      expect($("[id^=\"flash\"]")).toBeErrorFlashMessage();
+      expect(this.view.$("#flash-message")).toBeErrorFlashMessage();
     });
 
     it("sets the appropriate CSS class", function() {
diff --git a/spec/javascripts/helpers/SpecHelper.js b/spec/javascripts/helpers/SpecHelper.js
index 3a358571631a57a70107eeb8c7085defa5958beb..1ac82201799442d47b529e281154f55964ceddab 100644
--- a/spec/javascripts/helpers/SpecHelper.js
+++ b/spec/javascripts/helpers/SpecHelper.js
@@ -3,15 +3,12 @@
 var realXMLHttpRequest = window.XMLHttpRequest;
 
 // matches flash messages with success/error and contained text
-var flashMatcher = function(flash, id, text) {
+var flashMatcher = function(flash, klass, text) {
   var textContained = true;
-  if( text ) {
-    textContained = (flash.text().indexOf(text) !== -1);
+  if(text) {
+    textContained = (flash.text().trim().indexOf(text) !== -1);
   }
-
-  return flash.is(id) &&
-          flash.hasClass('expose') &&
-          textContained;
+  return flash.hasClass(klass) && flash.parent().hasClass("expose") && textContained;
 };
 
 // information for jshint
@@ -24,7 +21,7 @@ var customMatchers = {
     return {
       compare: function(actual, expected) {
         var result = {};
-        result.pass = flashMatcher(actual, '#flash_notice', expected);
+        result.pass = flashMatcher(actual, "alert-success", expected);
         return result;
       }
     };
@@ -33,7 +30,7 @@ var customMatchers = {
     return {
       compare: function(actual, expected) {
         var result = {};
-        result.pass = flashMatcher(actual, '#flash_error', expected);
+        result.pass = flashMatcher(actual, "alert-danger", expected);
         return result;
       }
     };
@@ -55,7 +52,7 @@ beforeEach(function() {
   var Page = Diaspora.Pages["TestPage"];
   $.extend(Page.prototype, Diaspora.EventBroker.extend(Diaspora.BaseWidget));
 
-  Diaspora.I18n.load({}, 'en', {});
+  Diaspora.I18n.load({}, "en", {});
 
   Diaspora.page = new Page();
   Diaspora.page.publish("page/ready", [$(document.body)]);
@@ -147,12 +144,12 @@ spec.clearLiveEventBindings = function() {
 };
 
 spec.content = function() {
-  return $('#jasmine_content');
+  return $("#jasmine_content");
 };
 
 // Loads fixure markup into the DOM as a child of the jasmine_content div
 spec.loadFixture = function(fixtureName) {
-  var $destination = $('#jasmine_content');
+  var $destination = $("#jasmine_content");
 
   // get the markup, inject it into the dom
   $destination.html(spec.fixtureHtml(fixtureName));
@@ -179,7 +176,7 @@ spec.fixtureHtml = function(fixtureName) {
 spec.retrieveFixture = function(fixtureName) {
 
   // construct a path to the fixture, including a cache-busting timestamp
-  var path = '/tmp/js_dom_fixtures/' + fixtureName + ".fixture.html?" + new Date().getTime();
+  var path = "/tmp/js_dom_fixtures/" + fixtureName + ".fixture.html?" + new Date().getTime();
   var xhr;
 
   // retrieve the fixture markup via xhr request to jasmine server
diff --git a/spec/javascripts/widgets/flash-messages-spec.js b/spec/javascripts/widgets/flash-messages-spec.js
deleted file mode 100644
index f2e02bd9c2ea01e070072d142ddd6b780c339311..0000000000000000000000000000000000000000
--- a/spec/javascripts/widgets/flash-messages-spec.js
+++ /dev/null
@@ -1,36 +0,0 @@
-describe("Diaspora", function() {
-  describe("Widgets", function() {
-    describe("FlashMessages", function() {
-      var flashMessages;
-
-      describe("animateMessages", function() {
-        beforeEach(function() {
-          flashMessages = Diaspora.BaseWidget.instantiate("FlashMessages");
-          $("#jasmine_content").html(
-            '<div id="flash_notice">' +
-              'flash message' +
-            '</div>'
-          );
-        });
-
-        it("is called when the DOM is ready", function() {
-          spyOn(flashMessages, "animateMessages").and.callThrough();
-          flashMessages.publish("widget/ready");
-          expect(flashMessages.animateMessages).toHaveBeenCalled();
-        });
-      });
-
-      describe("render", function() {
-        it("creates a new div for the message and calls flashes.animateMessages", function() {
-          spyOn(flashMessages, "animateMessages");
-          flashMessages.render({
-            success: true,
-            message: "success!"
-          });
-	  expect($("#flash_notice").length).toEqual(1);
-          expect(flashMessages.animateMessages).toHaveBeenCalled();
-        });
-      });
-    });
-  });
-});