diff --git a/vipra-backend/src/main/java/de/vipra/rest/resource/ArticleResource.java b/vipra-backend/src/main/java/de/vipra/rest/resource/ArticleResource.java
index 43a83f7ad6b834d3636c9301c5c3522a8313c3bd..436e729b4da1742fffa97896c89587233d5cec8e 100644
--- a/vipra-backend/src/main/java/de/vipra/rest/resource/ArticleResource.java
+++ b/vipra-backend/src/main/java/de/vipra/rest/resource/ArticleResource.java
@@ -3,13 +3,16 @@ package de.vipra.rest.resource;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
 import javax.servlet.ServletContext;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DefaultValue;
+import javax.ws.rs.FormParam;
 import javax.ws.rs.GET;
+import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
@@ -31,6 +34,7 @@ import de.vipra.util.StringUtils;
 import de.vipra.util.ex.ConfigException;
 import de.vipra.util.model.ArticleFull;
 import de.vipra.util.model.TextEntityFull;
+import de.vipra.util.model.Topic;
 import de.vipra.util.model.TopicModel;
 import de.vipra.util.model.TopicModelFull;
 import de.vipra.util.model.WordFull;
@@ -56,22 +60,29 @@ public class ArticleResource {
 		dbTopicModels = MongoService.getDatabaseService(config, TopicModelFull.class);
 	}
 
-	/**
-	 * @param topicModel
-	 * @param skip
-	 * @param limit
-	 * @param sortBy
-	 * @param fields
-	 * @param word
-	 * @return
-	 */
 	@GET
 	@Produces(MediaType.APPLICATION_JSON)
 	public Response getArticles(@QueryParam("topicModel") final String topicModel, @QueryParam("skip") final Integer skip,
 			@QueryParam("limit") final Integer limit, @QueryParam("sort") @DefaultValue("date") final String sortBy,
 			@QueryParam("fields") final String fields, @QueryParam("word") final String word, @QueryParam("entity") final String entity,
 			@QueryParam("excerpt") final String excerpt, @QueryParam("char") final String startChar, @QueryParam("contains") final String contains,
-			@QueryParam("from") final Long fromDate, @QueryParam("to") final Long toDate) {
+			@QueryParam("from") final Long fromDate, @QueryParam("to") final Long toDate, @QueryParam("topics") final List<String> topics) {
+		return processArticles(topicModel, skip, limit, sortBy, fields, word, entity, excerpt, startChar, contains, fromDate, toDate, topics);
+	}
+
+	@POST
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response postArticles(@FormParam("topicModel") final String topicModel, @FormParam("skip") final Integer skip,
+			@FormParam("limit") final Integer limit, @FormParam("sort") @DefaultValue("date") final String sortBy,
+			@FormParam("fields") final String fields, @FormParam("word") final String word, @FormParam("entity") final String entity,
+			@FormParam("excerpt") final String excerpt, @FormParam("char") final String startChar, @FormParam("contains") final String contains,
+			@FormParam("from") final Long fromDate, @FormParam("to") final Long toDate, @FormParam("topics") final List<String> topics) {
+		return processArticles(topicModel, skip, limit, sortBy, fields, word, entity, excerpt, startChar, contains, fromDate, toDate, topics);
+	}
+
+	private Response processArticles(final String topicModel, final Integer skip, final Integer limit, final String sortBy, final String fields,
+			final String word, final String entity, final String excerpt, final String startChar, final String contains, final Long fromDate,
+			final Long toDate, final List<String> topics) {
 		final ResponseWrapper<List<ArticleFull>> res = new ResponseWrapper<>();
 
 		if (topicModel == null || topicModel.trim().isEmpty()) {
@@ -114,6 +125,14 @@ public class ArticleResource {
 			if (toDate != null)
 				query.lte("date", new Date(toDate));
 
+			if (topics != null && !topics.isEmpty()) {
+				final List<Topic> ids = new ArrayList<>(topics.size());
+				for (final String s : topics)
+					if (ObjectId.isValid(s))
+						ids.add(new Topic(new ObjectId(s)));
+				query.in("topics.topic", ids);
+			}
+
 			final List<ArticleFull> articles = dbArticles.getMultiple(query);
 
 			if ((skip != null && skip > 0) || (limit != null && limit > 0))
diff --git a/vipra-ui/app/html/articles/index.html b/vipra-ui/app/html/articles/index.html
index fb929327cd0615ef90f9d9a32568cd1897afc161..43276e8928371e99c4ab58414aaa9f7ddf09e08e 100644
--- a/vipra-ui/app/html/articles/index.html
+++ b/vipra-ui/app/html/articles/index.html
@@ -82,6 +82,10 @@
                 </span>
               </div>
             </div>
+            <div class="form-group">
+              <label class="control-label">Topics</label>
+              <topic-chooser ng-model="articlesIndexModels.topics" />
+            </div>
           </div>
         </div>
       </div>
diff --git a/vipra-ui/app/html/directives/article-menu.html b/vipra-ui/app/html/directives/article-menu.html
index 4ae1d1143eba6caf251f6659f95ac3f00d25e246..362bdf1c4adc8886ffa22ba8d85537c5dcdf2f71 100644
--- a/vipra-ui/app/html/directives/article-menu.html
+++ b/vipra-ui/app/html/directives/article-menu.html
@@ -3,6 +3,7 @@
     <i class="fa fa-caret-down"></i>
   </a>
   <ul class="dropdown-menu" ng-class="{'dropdown-menu-right':dropdownRight}">
+    <li class="header">article</li>
     <li><a ui-sref="articles.show({id:article.id})">Show</a></li>
     <li><a ui-sref="articles.show.entities({id:article.id})">Entities</a></li>
     <li><a ui-sref="articles.show.words({id:article.id})">Words</a></li>
diff --git a/vipra-ui/app/html/directives/entity-menu.html b/vipra-ui/app/html/directives/entity-menu.html
index 11e89f94b4a5d1a56fc2b27d1715b478a0edc2a7..6bc02a74a769c1e5c6c518bbe5250c3b002dae8e 100644
--- a/vipra-ui/app/html/directives/entity-menu.html
+++ b/vipra-ui/app/html/directives/entity-menu.html
@@ -3,6 +3,7 @@
     <i class="fa fa-caret-down"></i>
   </a>
   <ul class="dropdown-menu" ng-class="{'dropdown-menu-right':dropdownRight}">
+    <li class="header">entity</li>
     <li><a ui-sref="entities.show({id:id})">Show</a></li>
     <li ng-if="entity.isWord"><a ui-sref="words.show({id:id})">Show word</a></li>
     <li><a ui-sref="entities.show.articles({id:id})">Articles</a></li>
diff --git a/vipra-ui/app/html/directives/topic-chooser.html b/vipra-ui/app/html/directives/topic-chooser.html
new file mode 100644
index 0000000000000000000000000000000000000000..762b40f57e879f3ff1ac80109a92afbcf87a903a
--- /dev/null
+++ b/vipra-ui/app/html/directives/topic-chooser.html
@@ -0,0 +1,20 @@
+<div class="form-control-box">
+  <div class="btn-group btn-group-justified">
+    <input type="text" class="form-control" ng-model="filter" placeholder="Filter..." />
+    <span class="glyphicon glyphicon-remove-circle searchclear" ng-click="filter=''"></span>
+  </div>
+  <div class="scroll-area message-container">
+    <div class="checkbox checkbox-condensed" ng-repeat="topic in topics | filter:{name:filter} track by topic.id">
+      <input tabindex="0" type="checkbox" ng-attr-id="{{::topic.id}}" ng-attr-ng-true-value="'{{::topic.id}}'" ng-false-value="undefined" ng-model="selectedTopics[$index]">
+      <label class="check" ng-attr-for="{{::topic.id}}" analytics-on analytics-event="Filter Topic Choice" analytics-category="Filter actions">
+        <span class="ellipsis menu-padding padding" ng-attr-title="{{topic.name}}">
+          <span class="title" ng-bind="topic.name"></span>
+        </span>
+        <topic-menu topic="topic" class="menu-button" />
+      </label>
+      <span class="colorbox" style="background:{{::topic.color}}"></span>
+    </div>
+    <span class="message text-muted" ng-if="!topics.length">No Topics</span>
+  </div>
+  <button type="button" class="btn btn-default btn-block" ng-click="selectedTopics=[]">All</button>
+</div>
\ No newline at end of file
diff --git a/vipra-ui/app/html/directives/topic-menu.html b/vipra-ui/app/html/directives/topic-menu.html
index e6984e1fb0eadb9b993d4b0ce8ec059595383954..45f5c379832d07be7ef1ca4742ccfa1726b98c44 100644
--- a/vipra-ui/app/html/directives/topic-menu.html
+++ b/vipra-ui/app/html/directives/topic-menu.html
@@ -3,6 +3,7 @@
     <i class="fa fa-caret-down"></i>
   </a>
   <ul class="dropdown-menu" ng-class="{'dropdown-menu-right':dropdownRight}">
+    <li class="header">topic</li>
     <li><a ui-sref="topics.show({id:topic.id})">Show</a></li>
     <li><a ui-sref="topics.show.sequences({id:topic.id})">Sequences</a></li>
     <li><a ui-sref="topics.show.articles({id:topic.id})">Articles</a></li>
diff --git a/vipra-ui/app/html/directives/word-menu.html b/vipra-ui/app/html/directives/word-menu.html
index cab3e5aae755297a5de6f80047e1c4c02433abf6..d90a6430dc93e29e6e3ee63e3e3942ce77e19641 100644
--- a/vipra-ui/app/html/directives/word-menu.html
+++ b/vipra-ui/app/html/directives/word-menu.html
@@ -3,6 +3,7 @@
     <i class="fa fa-caret-down"></i>
   </a>
   <ul class="dropdown-menu" ng-class="{'dropdown-menu-right':dropdownRight}">
+    <li class="header">word</li>
     <li><a ui-sref="words.show({id:id})">Show</a></li>
     <li ng-if="word.isEntity"><a ui-sref="entities.show({id:id})">Show entity</a></li>
     <li><a ui-sref="words.show.topics({id:id})">Topics</a></li>
diff --git a/vipra-ui/app/js/controllers.js b/vipra-ui/app/js/controllers.js
index f14631f66cf28b8c2462ee70eee00f7c01430f9b..18e01eb32771ddf01a8a77859dd9f1f93a962342 100644
--- a/vipra-ui/app/js/controllers.js
+++ b/vipra-ui/app/js/controllers.js
@@ -1169,13 +1169,18 @@
           sortkey: 'date',
           sortdir: true,
           page: 1,
-          limit: 50
+          limit: 50,
+          topics: []
         };
 
         $scope.reloadArticles = function() {
           $scope.loadingArticles = true;
 
-          ArticleFactory.query({
+          var topics = null;
+          if($scope.articlesIndexModels.topics && $scope.articlesIndexModels.topics.length)
+            topics = $scope.articlesIndexModels.topics;
+
+          (topics ? ArticleFactory.queryPOST : ArticleFactory.query)({
             skip: ($scope.articlesIndexModels.page - 1) * $scope.articlesIndexModels.limit,
             limit: $scope.articlesIndexModels.limit,
             sort: ($scope.articlesIndexModels.sortdir ? '' : '-') + $scope.articlesIndexModels.sortkey,
@@ -1183,7 +1188,8 @@
             char: $scope.articlesIndexModels.startChar,
             contains: $scope.articlesIndexModels.contains,
             from: $scope.articlesIndexModels.fromDate ? $scope.articlesIndexModels.fromDate.getTime() : null,
-            to: $scope.articlesIndexModels.toDate ? $scope.articlesIndexModels.toDate.getTime() : null
+            to: $scope.articlesIndexModels.toDate ? $scope.articlesIndexModels.toDate.getTime() : null,
+            topics: topics
           }, function(data, headers) {
             $scope.articles = data;
             $scope.articlesTotal = headers("V-Total");
@@ -1194,7 +1200,7 @@
           });
         };
 
-        $scope.$watchGroup(['articlesIndexModels.page', 'articlesIndexModels.sortkey', 'articlesIndexModels.sortdir', 'articlesIndexModels.fromDate', 'articlesIndexModels.toDate'], function() {
+        $scope.$watchGroup(['articlesIndexModels.page', 'articlesIndexModels.sortkey', 'articlesIndexModels.sortdir', 'articlesIndexModels.fromDate', 'articlesIndexModels.toDate', 'articlesIndexModels.topics'], function() {
           $scope.reloadArticles();
         });
 
diff --git a/vipra-ui/app/js/directives.js b/vipra-ui/app/js/directives.js
index b917830c3116fd3257685be425abfaf31a33b90b..d7b15828cfe12cbe9a6d8145805c6c2c85bcc720 100644
--- a/vipra-ui/app/js/directives.js
+++ b/vipra-ui/app/js/directives.js
@@ -612,4 +612,29 @@
     };
   }]);
 
+  app.directive('topicChooser', ['TopicFactory', function(TopicFactory) {
+    return {
+      scope: {
+        ngModel: '='
+      },
+      templateUrl: 'html/directives/topic-chooser.html',
+      link: function($scope) {
+        $scope.selectedTopics = [];
+
+        TopicFactory.query({
+          topicModel: $scope.$parent.rootModels.topicModel.id
+        }, function(data) {
+          $scope.topics = data;
+        });
+
+        $scope.$watch('selectedTopics', function() {
+          $scope.ngModel = [];
+          for(var i = 0; i < $scope.selectedTopics.length; i++)
+            if($scope.selectedTopics[i])
+              $scope.ngModel.push($scope.selectedTopics[i]);
+        }, true);
+      }
+    };
+  }]);
+
 })();
\ No newline at end of file
diff --git a/vipra-ui/app/js/factories.js b/vipra-ui/app/js/factories.js
index 49c0546dfed7b99b76585eaadc8bad979e37b5df..8f5c16dcf20c400d7a2e1f41d66828942f06eda1 100644
--- a/vipra-ui/app/js/factories.js
+++ b/vipra-ui/app/js/factories.js
@@ -39,7 +39,28 @@
   }]);
 
   app.factory('ArticleFactory', ['$myResource', function($myResource) {
-    return $myResource(Vipra.config.restUrl + '/articles/:id');
+    return $myResource(Vipra.config.restUrl + '/articles/:id', {}, {
+      queryPOST: {
+        method: 'POST',
+        isArray: true,
+        headers: {
+          'Content-Type': 'application/x-www-form-urlencoded'
+        },
+        transformRequest: function (data) {
+          var str = [];
+          for (var d in data)
+            if(data[d] !== undefined && data[d] !== null) {
+              if(angular.isArray(data[d])) {
+                for(var i = 0; i < data[d].length; i++)
+                  str.push(encodeURIComponent(d) + '=' + encodeURIComponent(data[d][i]));
+              } else {
+                str.push(encodeURIComponent(d) + '=' + encodeURIComponent(data[d]));
+              }
+            }
+          return str.join('&');
+        }
+      }
+    });
   }]);
 
   app.factory('TopicFactory', ['$myResource', function($myResource) {
diff --git a/vipra-ui/app/less/app.less b/vipra-ui/app/less/app.less
index d4280b0b9850e4c0e88c849cb5a1471e307cf4cb..b9a05d2bcdf4784b14508d2e35e1a247f0b6ee6c 100644
--- a/vipra-ui/app/less/app.less
+++ b/vipra-ui/app/less/app.less
@@ -271,6 +271,9 @@ td {
   width: 100%;
   vertical-align: middle;
   position: relative;
+  &.padding {
+    padding-right: 7px;
+  }
 }
 
 .valuebar {
@@ -1137,6 +1140,55 @@ entity-menu {
   }
 }
 
+.scroll-area {
+  overflow-y: auto;
+  height: 150px;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
+  box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
+  -webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
+  -o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
+  transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
+  padding: 3px 0 0px 3px;
+
+  .checkbox {
+    padding-bottom: 2px;
+  }
+
+  .menu-padding {
+    padding-left: 7px;
+  }
+}
+
+.form-control-box {
+  > * + *,
+  > * + * .form-control {
+    border-top-left-radius: 0;
+    border-top-right-radius: 0;
+    border-top: 0;
+  }
+  > *:not(:last-child),
+  > *:not(:last-child) .form-control {
+    border-bottom-left-radius: 0;
+    border-bottom-right-radius: 0;
+  }
+}
+
+.dropdown-menu {
+  .header {
+    padding: 3px 20px;
+    color: #fff;
+    background: #555;
+    font-weight: bold;
+    margin-top: -5px;
+    border-top-left-radius: 4px;
+    border-top-right-radius: 4px;
+    font-variant: small-caps;
+    margin-bottom: 5px;
+  }
+}
+
 [ng\:cloak], [ng-cloak], .ng-cloak {
   display: none !important;
 }