diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 7fee0c2a99..b81da2bb22 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -46,6 +46,11 @@ your_profile = Your Profile
 your_starred = Your Starred
 your_settings = Your Settings
 
+all = All
+sources = Sources
+mirrors = Mirrors
+collaborative = Collaborative
+
 activities = Activities
 pull_requests = Pull Requests
 issues = Issues
diff --git a/public/css/index.css b/public/css/index.css
index 774b559621..133af2690a 100644
--- a/public/css/index.css
+++ b/public/css/index.css
@@ -471,6 +471,17 @@ footer .ui.language .menu {
     padding-right: 30px !important;
   }
 }
+[v-cloak] {
+  display: none !important;
+}
+.repos-search {
+  padding-bottom: 0 !important;
+}
+.repos-filter {
+  margin-top: 0 !important;
+  border-bottom-width: 0 !important;
+  margin-bottom: 2px !important;
+}
 .markdown:not(code) {
   overflow: hidden;
   font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;
diff --git a/public/js/index.js b/public/js/index.js
index d79b94b92c..3152b2a5a4 100644
--- a/public/js/index.js
+++ b/public/js/index.js
@@ -1655,29 +1655,45 @@ $(function () {
     });
 });
 
-function initDashboardSearch() {
-    var el = document.getElementById('dashboard-repo-search');
-    if (!el) {
-        return;
-    }
+function initVueComponents(){
+    var vueDelimeters = ['${', '}'];
 
-    new Vue({
-        delimiters: ['${', '}'],
-        el: el,
+    Vue.component('repo-search', {
+        delimiters: vueDelimeters,
+        template: '#repo-search-template',
 
-        data: {
-            tab: 'repos',
-            repos: [],
-            searchQuery: '',
-            suburl: document.querySelector('meta[name=_suburl]').content,
-            uid: document.querySelector('meta[name=_context_uid]').content
+        props: {
+            searchLimit: {
+                type: Number,
+                default: 10
+            },
+            suburl: {
+                type: String,
+                required: true
+            },
+            uid: {
+                type: Number,
+                required: true
+            },
+        },
+
+        data: function() {
+            return {
+                tab: 'repos',
+                repos: [],
+                reposTotal: 0,
+                reposFilter: 'all',
+                searchQuery: '',
+                isLoading: false
+            }
         },
 
         mounted: function() {
             this.searchRepos();
 
+            var self = this;
             Vue.nextTick(function() {
-                document.querySelector('#search_repo').focus();
+                self.$refs.search.focus();
             });
         },
 
@@ -1686,19 +1702,45 @@ function initDashboardSearch() {
                 this.tab = t;
             },
 
-            searchKeyUp: function() {
-                this.searchRepos();
+            changeReposFilter: function(filter) {
+                this.reposFilter = filter;
+            },
+
+            showRepo: function(repo, filter) {
+                switch (filter) {
+                    case 'sources':
+                        return repo.owner.id == this.uid && !repo.mirror && !repo.fork;
+                    case 'forks':
+                        return repo.owner.id == this.uid && !repo.mirror && repo.fork;
+                    case 'mirrors':
+                        return repo.mirror;
+                    case 'collaborative':
+                        return repo.owner.id != this.uid;
+                    default:
+                        return true;
+                }
             },
 
             searchRepos: function() {
                 var self = this;
-                $.getJSON(this.searchURL(), function(result) {
-                    self.repos = result.data;
+                this.isLoading = true;
+                var searchedQuery = this.searchQuery;
+                $.getJSON(this.searchURL(), function(result, textStatus, request) {
+                    if (searchedQuery == self.searchQuery) {
+                        self.repos = result.data;
+                        if (searchedQuery == "") {
+                            self.reposTotal = request.getResponseHeader('X-Total-Count');
+                        }
+                    }
+                }).always(function() {
+                    if (searchedQuery == self.searchQuery) {
+                        self.isLoading = false;
+                    }
                 });
             },
 
             searchURL: function() {
-                return this.suburl + '/api/v1/repos/search?uid=' + this.uid + '&q=' + this.searchQuery;
+                return this.suburl + '/api/v1/repos/search?uid=' + this.uid + '&q=' + this.searchQuery + '&limit=' + this.searchLimit;
             },
 
             repoClass: function(repo) {
@@ -1713,5 +1755,25 @@ function initDashboardSearch() {
                 }
             }
         }
+    })
+}
+
+function initDashboardSearch() {
+    var el = document.getElementById('dashboard-repo-search');
+    if (!el) {
+        return;
+    }
+
+    initVueComponents();
+
+    new Vue({
+        delimiters: ['${', '}'],
+        el: el,
+
+        data: {
+            searchLimit: document.querySelector('meta[name=_search_limit]').content,
+            suburl: document.querySelector('meta[name=_suburl]').content,
+            uid: document.querySelector('meta[name=_context_uid]').content,
+        },
     });
 }
diff --git a/public/less/_base.less b/public/less/_base.less
index ba4821035b..572cec870e 100644
--- a/public/less/_base.less
+++ b/public/less/_base.less
@@ -464,3 +464,17 @@ footer {
     padding-right: 30px !important;
   }
 }
+
+[v-cloak] {
+	display: none !important;
+}
+
+.repos-search {
+    padding-bottom: 0 !important;
+}
+
+.repos-filter {
+    margin-top: 0 !important;
+    border-bottom-width: 0 !important;
+    margin-bottom: 2px !important;
+}
\ No newline at end of file
diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go
index edd6a72637..e44159817e 100644
--- a/routers/api/v1/repo/repo.go
+++ b/routers/api/v1/repo/repo.go
@@ -5,6 +5,7 @@
 package repo
 
 import (
+	"fmt"
 	"strings"
 
 	api "code.gitea.io/sdk/gitea"
@@ -91,6 +92,7 @@ func Search(ctx *context.APIContext) {
 	}
 
 	ctx.SetLinkHeader(int(count), setting.API.MaxResponseItems)
+	ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", count))
 	ctx.JSON(200, api.SearchResults{
 		OK:   true,
 		Data: results,
diff --git a/routers/user/home.go b/routers/user/home.go
index b2096bc2ce..1707d9d097 100644
--- a/routers/user/home.go
+++ b/routers/user/home.go
@@ -131,6 +131,7 @@ func Dashboard(ctx *context.Context) {
 	ctx.Data["Title"] = ctxUser.DisplayName() + " - " + ctx.Tr("dashboard")
 	ctx.Data["PageIsDashboard"] = true
 	ctx.Data["PageIsNews"] = true
+	ctx.Data["SearchLimit"] = setting.UI.User.RepoPagingNum
 
 	// Only user can have collaborative repositories.
 	if !ctxUser.IsOrganization() {
diff --git a/templates/base/footer.tmpl b/templates/base/footer.tmpl
index 923f39e85b..a0c14db218 100644
--- a/templates/base/footer.tmpl
+++ b/templates/base/footer.tmpl
@@ -45,10 +45,6 @@
 	<script src="{{AppSubUrl}}/js/draw.js"></script>
 {{end}}
 
-<!-- JavaScript -->
-<script src="{{AppSubUrl}}/js/semantic-2.2.1.min.js"></script>
-<script src="{{AppSubUrl}}/js/index.js?v={{MD5 AppVer}}"></script>
-
 <!-- Third-party libraries -->
 {{if .RequireHighlightJS}}
 	<script src="{{AppSubUrl}}/plugins/highlight-9.11.0/highlight.pack.js"></script>
@@ -66,5 +62,9 @@
 	<script src="{{AppSubUrl}}/js/libs/emojify-1.1.0.min.js"></script>
 	<script src="{{AppSubUrl}}/js/libs/clipboard-1.5.9.min.js"></script>
 	<script src="{{AppSubUrl}}/js/libs/vue.min.js"></script>
+
+	<!-- JavaScript -->
+	<script src="{{AppSubUrl}}/js/semantic-2.2.1.min.js"></script>
+	<script src="{{AppSubUrl}}/js/index.js?v={{MD5 AppVer}}"></script>
 </body>
 </html>
diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl
index bb6f1ecaf5..88d2b14a46 100644
--- a/templates/base/head.tmpl
+++ b/templates/base/head.tmpl
@@ -17,6 +17,9 @@
 	{{if .ContextUser}}
 		<meta name="_context_uid" content="{{.ContextUser.ID}}" />
 	{{end}}
+	{{if .SearchLimit}}
+		<meta name="_search_limit" content="{{.SearchLimit}}" />
+	{{end}}
 {{if .GoGetImport}}
 	<meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}">
 	<meta name="go-source" content="{{.GoGetImport}} _ {{.GoDocDirectory}} {{.GoDocFile}}">
diff --git a/templates/user/dashboard/dashboard.tmpl b/templates/user/dashboard/dashboard.tmpl
index 48d6966e18..01619ff4ee 100644
--- a/templates/user/dashboard/dashboard.tmpl
+++ b/templates/user/dashboard/dashboard.tmpl
@@ -8,105 +8,10 @@
 				{{template "user/dashboard/feeds" .}}
 			</div>
 			<div id="dashboard-repo-search" class="six wide column">
-				<div class="ui {{if not .ContextUser.IsOrganization}}three{{else}}two{{end}} item stackable tabable menu">
-					<a :class="{item: true, active: tab === 'repos'}" @click="changeTab('repos')">{{.i18n.Tr "repository"}}</a>
-					{{if not .ContextUser.IsOrganization}}
-						<a :class="{item: true, active: tab === 'orgs'}" @click="changeTab('orgs')">{{.i18n.Tr "organization"}}</a>
-					{{end}}
-					<a :class="{item: true, active: tab === 'mirrors'}" @click="changeTab('mirrors')">{{.i18n.Tr "mirror"}}</a>
-				</div>
-				<div v-if="tab === 'repos'" class="ui tab active list">
-					<div class="ui fluid input">
-						<input @keyUp="searchKeyUp" v-model="searchQuery" id="search_repo" placeholder="{{.i18n.Tr "home.search_repos"}}">
-					</div>
-					<h4 class="ui top attached header">
-						{{.i18n.Tr "home.my_repos"}} <span class="ui grey label">{{.ContextUser.NumRepos}}</span>
-						<div class="ui right">
-							<a class="poping up" href="{{AppSubUrl}}/repo/create" data-content="{{.i18n.Tr "new_repo"}}" data-variation="tiny inverted" data-position="left center">
-								<i class="plus icon"></i>
-								<span class="sr-only">{{.i18n.Tr "new_repo"}}</span>
-							</a>
-						</div>
-					</h4>
-					<div class="ui attached table segment">
-						<ul class="repo-owner-name-list">
-							<li v-for="repo in repos" :class="{'private': repo.private}">
-								<a :href="'{{AppSubUrl}}/' + repo.full_name">
-									<i :class="repoClass(repo)"></i>
-									<strong class="text truncate item-name">${ repo.full_name }</strong>
-									<span class="ui right text light grey">
-										${ repo.stars_count } <i class="octicon octicon-star rear"></i>
-									</span>
-								</a>
-							</li>
-							{{if gt .ContextUser.NumRepos .MaxShowRepoNum}}
-							<li>
-								<a href="{{.ContextUser.HomeLink}}">{{.i18n.Tr "home.show_more_repos"}}</a>
-							</li>
-							{{end}}
-						</ul>
-					</div>
-				</div>
-
-				{{if not .ContextUser.IsOrganization}}
-					<div v-if="tab === 'orgs'" class="ui tab active list">
-						<h4 class="ui top attached header">
-							{{.i18n.Tr "home.my_orgs"}} <span class="ui grey label">{{.ContextUser.GetOrganizationCount}}</span>
-							<div class="ui right">
-								{{if .SignedUser.CanCreateOrganization}}
-								<a class="poping up" href="{{AppSubUrl}}/org/create" data-content="{{.i18n.Tr "new_org"}}" data-variation="tiny inverted" data-position="left center">
-									<i class="plus icon"></i>
-									<span class="sr-only">{{.i18n.Tr "new_org"}}</span>
-								</a>
-								{{end}}
-							</div>
-						</h4>
-						<div class="ui attached table segment">
-							<ul class="repo-owner-name-list">
-								{{range .ContextUser.Orgs}}
-									<li>
-										<a href="{{AppSubUrl}}/{{.Name}}">
-											<i class="octicon octicon-organization"></i>
-											<strong class="text truncate item-name">{{.Name}}</strong>
-											<span class="ui right text light grey">
-												{{.NumRepos}} <i class="octicon octicon-repo rear"></i>
-											</span>
-										</a>
-									</li>
-								{{end}}
-							</ul>
-						</div>
-					</div>
-				{{end}}
-
-				<div v-if="tab === 'mirrors'" class="ui tab active list">
-					<h4 class="ui top attached header">
-						{{.i18n.Tr "home.my_mirrors"}} <span class="ui grey label">{{.MirrorCount}}</span>
-						<div class="ui right">
-							<a class="poping up" href="{{AppSubUrl}}/repo/migrate?mirror=1" data-content="{{.i18n.Tr "new_mirror"}}" data-variation="tiny inverted" data-position="left center">
-								<i class="plus icon"></i>
-								<span class="sr-only">{{.i18n.Tr "new_mirror"}}</span>
-							</a>
-						</div>
-					</h4>
-					<div class="ui attached table segment">
-						<ul class="repo-owner-name-list">
-							{{range .Mirrors}}
-								<li {{if .IsPrivate}}class="private"{{end}}>
-									<a href="{{AppSubUrl}}/{{$.ContextUser.Name}}/{{.Name}}">
-										<i class="octicon octicon-repo-clone"></i>
-										<strong class="text truncate item-name">{{.Name}}</strong>
-										<span class="ui right text light grey">
-											{{.Interval}}H <i class="octicon octicon-sync rear"></i>
-										</span>
-									</a>
-								</li>
-							{{end}}
-						</ul>
-					</div>
-				</div>
+				<repo-search :search-limit="searchLimit" :suburl="suburl" :uid="uid"><i class="fa fa-spinner fa-spin"></i></repo-search>
 			</div>
 		</div>
 	</div>
 </div>
+{{template "user/dashboard/repo-search" .}}
 {{template "base/footer" .}}
diff --git a/templates/user/dashboard/repo-search.tmpl b/templates/user/dashboard/repo-search.tmpl
new file mode 100644
index 0000000000..6b8bde5865
--- /dev/null
+++ b/templates/user/dashboard/repo-search.tmpl
@@ -0,0 +1,81 @@
+<script type="text/x-template" id="repo-search-template">
+    <div>
+        {{if not .ContextUser.IsOrganization}}
+        <div class="ui two item stackable tabable menu">
+            <a :class="{item: true, active: tab === 'repos'}" @click="changeTab('repos')">{{.i18n.Tr "repository"}}</a>
+            <a :class="{item: true, active: tab === 'orgs'}" @click="changeTab('orgs')">{{.i18n.Tr "organization"}}</a>
+        </div>
+        {{end}}
+        <div v-if="tab === 'repos'" class="ui tab active list">
+            <h4 class="ui top attached header">
+                {{.i18n.Tr "home.my_repos"}} <span class="ui grey label">${ reposTotal }</span>
+                <div class="ui right">
+                    <a class="poping up" href="{{AppSubUrl}}/repo/create" data-content="{{.i18n.Tr "new_repo"}}" data-variation="tiny inverted" data-position="left center">
+                        <i class="plus icon"></i>
+                        <span class="sr-only">{{.i18n.Tr "new_repo"}}</span>
+                    </a>
+                </div>
+            </h4>
+            <div class="ui attached secondary segment repos-search">
+                <div class="ui fluid icon input" :class="{loading: isLoading}">
+                    <input @input="searchRepos" v-model="searchQuery" ref="search" placeholder="{{.i18n.Tr "home.search_repos"}}">
+                    <i class="search icon"></i>
+                </div>
+                <div class="ui secondary tiny pointing borderless menu center aligned grid repos-filter">
+                    <a class="item" :class="{active: reposFilter === 'all'}" @click="changeReposFilter('all')">{{.i18n.Tr "all"}}</a>
+                    <a class="item" :class="{active: reposFilter === 'sources'}" @click="changeReposFilter('sources')">{{.i18n.Tr "sources"}}</a>
+                    <a class="item" :class="{active: reposFilter === 'forks'}" @click="changeReposFilter('forks')">{{.i18n.Tr "forks"}}</a>
+                    <a class="item" :class="{active: reposFilter === 'mirrors'}" @click="changeReposFilter('mirrors')">{{.i18n.Tr "mirrors"}}</a>
+                    <a class="item" :class="{active: reposFilter === 'collaborative'}" @click="changeReposFilter('collaborative')">{{.i18n.Tr "collaborative"}}</a>
+                </div>
+            </div>
+            <div class="ui attached table segment">
+                <ul class="repo-owner-name-list">
+                    <li v-for="repo in repos" :class="{'private': repo.private}" v-show="showRepo(repo, reposFilter)">
+                        <a :href="'{{AppSubUrl}}/' + repo.full_name">
+                            <i :class="repoClass(repo)"></i>
+                            <strong class="text truncate item-name">${ repo.full_name }</strong>
+                            <span class="ui right text light grey">
+                                ${ repo.stars_count } <i class="octicon octicon-star rear"></i>
+                            </span>
+                        </a>
+                    </li>
+                    <li v-if="repos.length < reposTotal">
+                        <a href="{{.ContextUser.HomeLink}}">{{.i18n.Tr "home.show_more_repos"}}</a>
+                    </li>
+                </ul>
+            </div>
+        </div>
+
+        {{if not .ContextUser.IsOrganization}}
+            <div v-if="tab === 'orgs'" class="ui tab active list">
+                <h4 class="ui top attached header">
+                    {{.i18n.Tr "home.my_orgs"}} <span class="ui grey label">{{.ContextUser.GetOrganizationCount}}</span>
+                    <div class="ui right">
+                        {{if .SignedUser.CanCreateOrganization}}
+                        <a class="poping up" href="{{AppSubUrl}}/org/create" data-content="{{.i18n.Tr "new_org"}}" data-variation="tiny inverted" data-position="left center">
+                            <i class="plus icon"></i>
+                            <span class="sr-only">{{.i18n.Tr "new_org"}}</span>
+                        </a>
+                        {{end}}
+                    </div>
+                </h4>
+                <div class="ui attached table segment">
+                    <ul class="repo-owner-name-list">
+                        {{range .ContextUser.Orgs}}
+                            <li>
+                                <a href="{{AppSubUrl}}/{{.Name}}">
+                                    <i class="octicon octicon-organization"></i>
+                                    <strong class="text truncate item-name">{{.Name}}</strong>
+                                    <span class="ui right text light grey">
+                                        {{.NumRepos}} <i class="octicon octicon-repo rear"></i>
+                                    </span>
+                                </a>
+                            </li>
+                        {{end}}
+                    </ul>
+                </div>
+            </div>
+        {{end}}
+    </div>
+</script>
\ No newline at end of file