diff --git a/res/css/_animations.sass b/res/css/_animations.sass
index 03993488a66c49dd76d7fea702ebff5816520024..db3311c0760d8bba0687bcfee15c5199daa42c2a 100644
--- a/res/css/_animations.sass
+++ b/res/css/_animations.sass
@@ -23,4 +23,26 @@
 
   to
     margin-top: 0
-    opacity: 1
\ No newline at end of file
+    opacity: 1
+
+@keyframes indeterminate
+  0%
+    left: -35%
+    right: 100%
+  60%
+    left: 100%
+    right: -90%
+  100%
+    left: 100%
+    right: -90%
+
+@keyframes indeterminate-short
+  0%
+    left: -200%
+    right: 100%
+  60%
+    left: 107%
+    right: -8%
+  100%
+    left: 107%
+    right: -8%
\ No newline at end of file
diff --git a/res/css/_content.sass b/res/css/_content.sass
index a4d6c9e5f90da229f083a3ddd7bb48005775fb45..469fefed5395a9e5caafd6bdcc70077c43b9150f 100644
--- a/res/css/_content.sass
+++ b/res/css/_content.sass
@@ -14,6 +14,21 @@
     padding-right: 0
     padding-bottom: 0
 
+  .error
+    text-align: center
+    height: 100%
+    margin: 4rem
+    animation-duration: 0.6s
+    animation-name: slidein
+
+    img
+      max-width: 100%
+
+    h1
+      margin-top: 2rem
+      color: #777
+      font-weight: normal
+
   .buffer
     display: block
     margin-top: 0
diff --git a/res/css/_loading.sass b/res/css/_loading.sass
new file mode 100644
index 0000000000000000000000000000000000000000..06b73b28a3a52c65d14f5c6a383ceae73e9820fe
--- /dev/null
+++ b/res/css/_loading.sass
@@ -0,0 +1,38 @@
+.progress 
+  position: absolute
+  height: 4px
+  display: block
+  background-color: rgba(255,255,255,0.2)
+  overflow: hidden
+  transition: opacity 400ms
+  bottom: 0
+  left: 0
+  right: 0
+
+  &:not(.visible)
+    opacity: 0
+
+  .indeterminate
+    background-color: rgba(255,255,255,0.8)
+
+    &:before
+      content: ''
+      position: absolute
+      background-color: inherit
+      top: 0
+      left: 0
+      bottom: 0
+      will-change: left, right
+      animation: indeterminate 4.2s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite
+
+    &:after
+      content: ''
+      position: absolute
+      background-color: inherit
+      top: 0
+      left: 0
+      bottom: 0
+      will-change: left, right
+      animation: indeterminate-short 4.2s cubic-bezier(0.165, 0.84, 0.44, 1) infinite
+      animation-delay: 2.25s
+
diff --git a/res/css/_nav.sass b/res/css/_nav.sass
index 63755938312f9f689079319856212a3f9217f792..3a92ce032807e37d10e3d69cf40023fbbfa93c1f 100644
--- a/res/css/_nav.sass
+++ b/res/css/_nav.sass
@@ -189,6 +189,12 @@
         .icon
           color: #757575
 
+      .progress
+        background-color: rgba(117, 117, 117, 0.2)
+
+        .indeterminate
+          background-color: rgba(117, 117, 117, 0.8)
+
     .history
       transform: translateY(0)
 
diff --git a/res/css/search.css b/res/css/search.css
index f8fccc34f09c9b213a711df7daca411b45683585..66ec6bb91aff4c0d864f812d62082360eef6fd3a 100644
--- a/res/css/search.css
+++ b/res/css/search.css
@@ -61,6 +61,40 @@ body {
   visibility: hidden !important;
   display: none !important; }
 
+.progress {
+  position: absolute;
+  height: 4px;
+  display: block;
+  background-color: rgba(255, 255, 255, 0.2);
+  overflow: hidden;
+  transition: opacity 400ms;
+  bottom: 0;
+  left: 0;
+  right: 0; }
+  .progress:not(.visible) {
+    opacity: 0; }
+  .progress .indeterminate {
+    background-color: rgba(255, 255, 255, 0.8); }
+    .progress .indeterminate:before {
+      content: '';
+      position: absolute;
+      background-color: inherit;
+      top: 0;
+      left: 0;
+      bottom: 0;
+      will-change: left, right;
+      animation: indeterminate 4.2s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite; }
+    .progress .indeterminate:after {
+      content: '';
+      position: absolute;
+      background-color: inherit;
+      top: 0;
+      left: 0;
+      bottom: 0;
+      will-change: left, right;
+      animation: indeterminate-short 4.2s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
+      animation-delay: 2.25s; }
+
 .nav {
   position: fixed;
   left: 0;
@@ -225,6 +259,10 @@ body {
           color: #757575; }
     .nav.focus .bar .container .icon {
       color: #757575; }
+    .nav.focus .bar .progress {
+      background-color: rgba(117, 117, 117, 0.2); }
+      .nav.focus .bar .progress .indeterminate {
+        background-color: rgba(117, 117, 117, 0.8); }
   .nav.focus .history {
     transform: translateY(0); }
   .nav.focus + .results {
@@ -909,6 +947,18 @@ body {
       padding-left: 0;
       padding-right: 0;
       padding-bottom: 0; } }
+  .results .error {
+    text-align: center;
+    height: 100%;
+    margin: 4rem;
+    animation-duration: 0.6s;
+    animation-name: slidein; }
+    .results .error img {
+      max-width: 100%; }
+    .results .error h1 {
+      margin-top: 2rem;
+      color: #777;
+      font-weight: normal; }
   .results .buffer {
     display: block;
     margin-top: 0;
@@ -1239,3 +1289,25 @@ body {
   to {
     margin-top: 0;
     opacity: 1; } }
+
+@keyframes indeterminate {
+  0% {
+    left: -35%;
+    right: 100%; }
+  60% {
+    left: 100%;
+    right: -90%; }
+  100% {
+    left: 100%;
+    right: -90%; } }
+
+@keyframes indeterminate-short {
+  0% {
+    left: -200%;
+    right: 100%; }
+  60% {
+    left: 107%;
+    right: -8%; }
+  100% {
+    left: 107%;
+    right: -8%; } }
diff --git a/res/css/search.sass b/res/css/search.sass
index f5db1ffe420543054694fc86d86138dccbec0571..1d11da7a872e1f90ea999a4a54aaa277598af26a 100644
--- a/res/css/search.sass
+++ b/res/css/search.sass
@@ -24,6 +24,7 @@ body
   visibility: hidden !important
   display: none !important
 
+@import "loading"
 @import "nav"
 @import "searchoptions"
 @import "content"
diff --git a/res/js/component/app.js b/res/js/component/app.js
index d56ee1cc7001c3434443ac8344c4bf62462c757b..9f8a11025ad7a61254a9e32e43d9da78a6ac77d5 100644
--- a/res/js/component/app.js
+++ b/res/js/component/app.js
@@ -4,6 +4,7 @@ class App {
         this.navigation = new Navigation();
         this.buffers = [];
         this.loadingQuery = 0;
+        this.error = null;
         if (Storage.exists('language')) {
             moment.locale(Storage.get('language'));
         }
@@ -31,6 +32,7 @@ class App {
     }
     search(query, sender, buffer, network, before, since) {
         this.clear();
+        this.navigation.loading.show();
         this.navigation.input.blur();
         this.navigation.historyView.resetNavigation();
         this.navigation.historyView.add(new HistoryElement(query));
@@ -43,12 +45,16 @@ class App {
         load('web/search/', statehandler.parse()).then(result => {
             if (this.loadingQuery !== queryId)
                 return;
+            this.navigation.loading.hide();
             this.buffers = result.map(buffer => {
                 return new Buffer(buffer.bufferid, buffer.buffername, buffer.networkname, buffer.hasmore, buffer.messages.map(msg => {
                     return new Context(new Message(msg.messageid, msg.type, msg.time, msg.sender, msg.message, true));
                 }));
             });
             this.buffers.forEach(buffer => this.insert(buffer));
+            if (this.buffers.length === 0) {
+                this.showError(translation.error.none_found);
+            }
         });
     }
     clear() {
@@ -56,12 +62,19 @@ class App {
             const buffer = this.buffers.pop();
             this.resultContainer.removeChild(buffer.elem);
         }
+        if (this.error) {
+            this.resultContainer.removeChild(this.error.elem);
+        }
     }
     clearAll() {
         this.clear();
         this.navigation.historyView.clear();
         statehandler.clear();
     }
+    showError(text) {
+        this.error = new Error(text);
+        this.resultContainer.appendChild(this.error.elem);
+    }
     insert(buffer) {
         this.resultContainer.appendChild(buffer.elem);
         buffer.addEventListener('loadMore', () => this.bufferLoadMore(buffer));
diff --git a/res/js/component/app.jsx b/res/js/component/app.jsx
index 115694d047d04e651e87b2919fe568210d634dde..65fde68e421111c5ab73aa5138a9c15317dc9cd1 100644
--- a/res/js/component/app.jsx
+++ b/res/js/component/app.jsx
@@ -6,6 +6,7 @@ class App {
         this.buffers = [];
 
         this.loadingQuery = 0;
+        this.error = null;
 
         if (Storage.exists('language')) {
             moment.locale(Storage.get('language'));
@@ -32,6 +33,8 @@ class App {
 
     search(query, sender, buffer, network, before, since) {
         this.clear();
+        this.navigation.loading.show();
+
         this.navigation.input.blur();
         this.navigation.historyView.resetNavigation();
         this.navigation.historyView.add(new HistoryElement(query));
@@ -47,12 +50,16 @@ class App {
             if (this.loadingQuery !== queryId)
                 return;
 
+            this.navigation.loading.hide();
             this.buffers = result.map((buffer) => {
                 return new Buffer(buffer.bufferid, buffer.buffername, buffer.networkname, buffer.hasmore, buffer.messages.map((msg) => {
                     return new Context(new Message(msg.messageid, msg.type, msg.time, msg.sender, msg.message, true));
                 }));
             });
             this.buffers.forEach((buffer) => this.insert(buffer));
+            if (this.buffers.length === 0) {
+                this.showError(translation.error.none_found);
+            }
         });
     }
 
@@ -61,6 +68,10 @@ class App {
             const buffer = this.buffers.pop();
             this.resultContainer.removeChild(buffer.elem);
         }
+
+        if (this.error) {
+            this.resultContainer.removeChild(this.error.elem);
+        }
     }
 
     clearAll() {
@@ -69,6 +80,11 @@ class App {
         statehandler.clear();
     }
 
+    showError(text) {
+        this.error = new Error(text);
+        this.resultContainer.appendChild(this.error.elem);
+    }
+
     insert(buffer) {
         this.resultContainer.appendChild(buffer.elem);
         buffer.addEventListener("loadMore", () => this.bufferLoadMore(buffer));
diff --git a/res/js/component/error.js b/res/js/component/error.js
new file mode 100644
index 0000000000000000000000000000000000000000..6633e396b6af0c48990d2cc7646141e711a31087
--- /dev/null
+++ b/res/js/component/error.js
@@ -0,0 +1,18 @@
+class Error {
+    constructor(text) {
+        this.render(text);
+    }
+    render(text) {
+        return this.elem = function () {
+            var $$a = document.createElement('div');
+            $$a.setAttribute('class', 'error');
+            var $$b = document.createElement('img');
+            $$b.setAttribute('src', 'res/icons/error.png');
+            $$a.appendChild($$b);
+            var $$c = document.createElement('h1');
+            $$a.appendChild($$c);
+            $$c.appendChildren(text);
+            return $$a;
+        }.call(this);
+    }
+}
\ No newline at end of file
diff --git a/res/js/component/error.jsx b/res/js/component/error.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..ddb9a7389b51d9ad06c4c23d9c5b7ab4f769fd2e
--- /dev/null
+++ b/res/js/component/error.jsx
@@ -0,0 +1,14 @@
+class Error {
+    constructor(text) {
+        this.render(text);
+    }
+
+    render(text) {
+        return this.elem = (
+            <div className="error">
+                <img src="res/icons/error.png"/>
+                <h1>{text}</h1>
+            </div>
+        );
+    }
+}
\ No newline at end of file
diff --git a/res/js/component/loading.js b/res/js/component/loading.js
new file mode 100644
index 0000000000000000000000000000000000000000..158a3ae08112a6f523802cf9924431c9ce32e104
--- /dev/null
+++ b/res/js/component/loading.js
@@ -0,0 +1,21 @@
+class Loading {
+    constructor() {
+        this.render();
+    }
+    render() {
+        return this.elem = function () {
+            var $$a = document.createElement('div');
+            $$a.setAttribute('class', 'progress');
+            var $$b = document.createElement('div');
+            $$b.setAttribute('class', 'indeterminate');
+            $$a.appendChild($$b);
+            return $$a;
+        }.call(this);
+    }
+    show() {
+        this.elem.classList.add('visible');
+    }
+    hide() {
+        this.elem.classList.remove('visible');
+    }
+}
\ No newline at end of file
diff --git a/res/js/component/loading.jsx b/res/js/component/loading.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..8d72d35f8fda04edc795f421c74407dfa591bb1f
--- /dev/null
+++ b/res/js/component/loading.jsx
@@ -0,0 +1,22 @@
+class Loading {
+    constructor() {
+        this.render();
+    }
+
+    render() {
+        return this.elem = (
+            <div className="progress">
+                <div className="indeterminate">
+                </div>
+            </div>
+        );
+    }
+
+    show() {
+        this.elem.classList.add("visible");
+    }
+
+    hide() {
+        this.elem.classList.remove("visible");
+    }
+}
\ No newline at end of file
diff --git a/res/js/component/nav.js b/res/js/component/nav.js
index fa2b31e0f43a14e484adfcdf81977a5ee108eb41..701376af5db3ed667bcbb3162c0e2bac2428bee9 100644
--- a/res/js/component/nav.js
+++ b/res/js/component/nav.js
@@ -52,6 +52,7 @@ class Navigation extends Component {
             $$i.appendChild($$j);
             var $$k = document.createTextNode('exit_to_app');
             $$j.appendChild($$k);
+            $$b.appendChildren((this.loading = new Loading()).elem);
             $$a.appendChildren((this.historyView = new HistoryView()).elem);
             return $$a;
         }.call(this);
diff --git a/res/js/component/nav.jsx b/res/js/component/nav.jsx
index b7389c7305246ddb6d5f0d9085f3f0c9c46abc18..c0f064b94814c468177aaa3632836294341fe78b 100644
--- a/res/js/component/nav.jsx
+++ b/res/js/component/nav.jsx
@@ -36,6 +36,7 @@ class Navigation extends Component {
                                className="icon">exit_to_app</a>
                         </div>
                     </div>
+                    {(this.loading = new Loading()).elem}
                 </div>
                 {(this.historyView = new HistoryView()).elem}
             </div>
diff --git a/templates/search.phtml b/templates/search.phtml
index a72a637f71a853bb8432c6554bc9d8384b789df6..3b032a48081dc15f78fea4c675858a0e71a76910 100644
--- a/templates/search.phtml
+++ b/templates/search.phtml
@@ -42,6 +42,8 @@
 <script src="res/js/component/nav.js"></script>
 <script src="res/js/component/message.js"></script>
 <script src="res/js/component/loadmore.js"></script>
+<script src="res/js/component/error.js"></script>
+<script src="res/js/component/loading.js"></script>
 <script src="res/js/component/context.js"></script>
 <script src="res/js/component/buffer.js"></script>
 <script src="res/js/component/app.js"></script>
diff --git a/translations/de.json b/translations/de.json
index e6fe6c122aa60e928adbb07ae89a7355c3144acf..8937f7110a9812d46de085b72e1051d852cea970 100644
--- a/translations/de.json
+++ b/translations/de.json
@@ -24,6 +24,9 @@
       "error_unauthed": "Sie müssen angemeldet sein, um diese Seite zu nutzen."
     }
   },
+  "error": {
+    "none_found": "Keine Ergebnisse gefunden"
+  },
   "search": "Suchen",
   "logout": "Abmelden",
   "title": "QuasselSearch"
diff --git a/translations/en.json b/translations/en.json
index bfde2bd48ea9ef86655731a2fea57684fd481bbc..87a4f4e189d8808b2fe3abc09db33e6d26a79b86 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -24,6 +24,9 @@
       "error_unauthed": "You need to be logged in to access this page."
     }
   },
+  "error": {
+    "none_found": "No results found"
+  },
   "search": "Search",
   "logout": "Logout",
   "title": "QuasselSearch"