diff --git a/qml.qrc b/qml.qrc
index 3b8d6be22ba486a52d4f3231cbcbbb94a5d90394..8f55670bbdaa4cefb546db94b0ffcff32bae945c 100644
--- a/qml.qrc
+++ b/qml.qrc
@@ -136,5 +136,6 @@
         <file>src/mainview/js/screenrubberbandcreation.js</file>
         <file>src/mainview/js/contactpickercreation.js</file>
         <file>src/mainview/js/pluginhandlerpickercreation.js</file>
+        <file>src/mainview/components/FilterTabButton.qml</file>
     </qresource>
 </RCC>
diff --git a/src/mainview/components/FilterTabButton.qml b/src/mainview/components/FilterTabButton.qml
new file mode 100644
index 0000000000000000000000000000000000000000..5a16bb0594e7b1ecdd7bbb8b5a6a1b6909d89549
--- /dev/null
+++ b/src/mainview/components/FilterTabButton.qml
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2020-2021 by Savoir-faire Linux
+ * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
+ * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Layouts 1.14
+import QtGraphicalEffects 1.14
+
+import net.jami.Models 1.0
+import net.jami.Adapters 1.0
+import net.jami.Constants 1.0
+
+import "../../commoncomponents"
+
+TabButton {
+    id: root
+
+    property var tabBar: undefined
+    property alias labelText: label.text
+    property alias acceleratorSequence: accelerator.sequence
+    property int badgeCount
+    signal selected
+
+    hoverEnabled: true
+    onClicked: selected()
+
+    Rectangle {
+        id: rect
+
+        width: tabBar.width / 2 + 1
+        height: tabBar.height
+        color: root.hovered ?
+                   JamiTheme.hoverColor :
+                   JamiTheme.backgroundColor
+
+        Text {
+            id: label
+
+            anchors.horizontalCenter: rect.horizontalCenter
+            anchors.bottom: rect.bottom
+            anchors.bottomMargin: 12
+
+            horizontalAlignment: Text.AlignHCenter
+            verticalAlignment: Text.AlignVCenter
+
+            font.pointSize: JamiTheme.textFontSize
+            color: Qt.lighter(JamiTheme.textColor, root.down ? 1.0 : 1.5)
+        }
+
+        Rectangle {
+            id: badgeRect
+
+            anchors.left: label.right
+            anchors.leftMargin: 4
+            anchors.verticalCenter: label.verticalCenter
+            anchors.verticalCenterOffset : -5
+
+            width: 12
+            height: 12
+
+            visible: badgeCount > 0
+
+            Text {
+                anchors.centerIn: badgeRect
+                text: badgeCount > 9 ? "···" : badgeCount
+                color: JamiTheme.whiteColor
+                font.pointSize: JamiTheme.indicatorFontSize
+            }
+            radius: 30
+            color: JamiTheme.notificationBlue
+        }
+
+        Rectangle {
+            width: rect.width
+            anchors.bottom: rect.bottom
+            height: 2
+            color: root.down ? JamiTheme.textColor : "transparent"
+        }
+    }
+
+    Shortcut {
+        id: accelerator
+        context: Qt.ApplicationShortcut
+        enabled: rect.visible
+        onActivated: selected()
+    }
+}
diff --git a/src/mainview/components/SidePanelTabBar.qml b/src/mainview/components/SidePanelTabBar.qml
index 6cfd0248f8a85e9ce680f246715066976004786a..cd5f51ab9b1d52d6a3e614a45b1873f14288df65 100644
--- a/src/mainview/components/SidePanelTabBar.qml
+++ b/src/mainview/components/SidePanelTabBar.qml
@@ -1,7 +1,7 @@
-
 /*
- * Copyright (C) 2020 by Savoir-faire Linux
+ * Copyright (C) 2020-2021 by Savoir-faire Linux
  * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
+ * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -28,6 +28,12 @@ import net.jami.Constants 1.0
 
 import "../../commoncomponents"
 
+// TODO:
+// - totalUnreadMessagesCount and pendingRequestCount could be
+//   properties of ConversationsAdapter
+// - onCurrentTypeFilterChanged shouldn't need to update the smartlist
+// - tabBarVisible could be factored out
+
 TabBar {
     id: tabBar
 
@@ -48,200 +54,34 @@ TabBar {
     }
 
     function selectTab(tabIndex) {
-        ConversationsAdapter.currentTypeFilter = tabIndex ===
-                SidePanelTabBar.Conversations ? AccountAdapter.getCurrentAccountType() :
-                                                Profile.Type.PENDING
+        ConversationsAdapter.currentTypeFilter =
+                (tabIndex === SidePanelTabBar.Conversations) ?
+                    AccountAdapter.currentAccountType :
+                    Profile.Type.PENDING
     }
 
-    property alias converstationTabWidth: pageOne.width
-    property alias invitationTabWidth: pageTwo.width
-    property alias converstationTabHeight: pageOne.height
-    property alias invitationTabHeight: pageTwo.height
-    property real opacityDegree: 0.5
-
     visible: tabBarVisible
 
     currentIndex: 0
 
-    TabButton {
-
+    FilterTabButton {
         id: pageOne
-        down: true
-
-
-        background: Rectangle {
-
-            id: buttonRectOne
-            width: tabBar.width / 2 + 1
-            height: tabBar.height
-            color: JamiTheme.backgroundColor
-
-            Text {
-                id: textConvElement
-
-                anchors.horizontalCenter: buttonRectOne.horizontalCenter
-                anchors.bottom: buttonRectOne.bottom
-                anchors.bottomMargin: 12
-
-                horizontalAlignment: Text.AlignHCenter
-                verticalAlignment: Text.AlignVCenter
-
-                text: JamiStrings.conversations
-                font.pointSize: JamiTheme.textFontSize
-                opacity: pageOne.down == true ? 1.0 : opacityDegree
-                color: JamiTheme.textColor
-            }
-
-            Rectangle {
-                id: totalUnreadMessagesCountRect
-
-                anchors.left: textConvElement.right
-                anchors.leftMargin: 4
-                anchors.verticalCenter: textConvElement.verticalCenter
-                anchors.verticalCenterOffset : -5
-
-                width: 12
-                height: 12
-
-                visible: totalUnreadMessagesCount > 0
-
-                Text {
-                    id: totalUnreadMessagesCountText
-
-                    anchors.centerIn: totalUnreadMessagesCountRect
-
-                    text: totalUnreadMessagesCount > 9 ? "···" : totalUnreadMessagesCount
-                    color: "white"
-                    font.pointSize: JamiTheme.indicatorFontSize
-                }
-                radius: 30
-                color: JamiTheme.notificationBlue
-            }
-
-            Rectangle {
-                id: markerTabOne
-                width: buttonRectOne.width
-                anchors.bottom: buttonRectOne.bottom
-                height: 2
-                color: pageOne.down == true ? JamiTheme.textColor : "transparent"
-            }
-
-            MouseArea {
-                anchors.fill: parent
-                hoverEnabled: true
-                onPressed: {
-                    selectTab(SidePanelTabBar.Conversations)
-                }
-                onReleased: {
-                    buttonRectOne.color = Qt.binding(function(){return JamiTheme.backgroundColor})
-                }
-                onEntered: {
-                    buttonRectOne.color = Qt.binding(function(){return JamiTheme.hoverColor})
-                }
-                onExited: {
-                    buttonRectOne.color = Qt.binding(function(){return JamiTheme.backgroundColor})
-                }
-            }
 
-            Shortcut {
-                sequence: "Ctrl+L"
-                context: Qt.ApplicationShortcut
-                enabled: buttonRectOne.visible
-                onActivated: {
-                    selectTab(SidePanelTabBar.Conversations)
-                }
-            }
-        }
+        tabBar: parent
+        down: true
+        labelText: JamiStrings.conversations
+        onSelected: selectTab(SidePanelTabBar.Conversations)
+        badgeCount: totalUnreadMessagesCount
+        acceleratorSequence: "Ctrl+L"
     }
 
-    TabButton {
-
+    FilterTabButton {
         id: pageTwo
 
-        background: Rectangle {
-            id: buttonRectTwo
-
-            width: tabBar.width / 2
-            height: tabBar.height
-            color: JamiTheme.backgroundColor
-
-            Text {
-                id: textInvElement
-
-                anchors.horizontalCenter: buttonRectTwo.horizontalCenter
-                anchors.bottom: buttonRectTwo.bottom
-                anchors.bottomMargin: 12
-
-                horizontalAlignment: Text.AlignHCenter
-                verticalAlignment: Text.AlignVCenter
-
-                font.pointSize: JamiTheme.textFontSize
-
-                text: JamiStrings.invitations
-                //opacity: enabled ? 1.0 : 0.3
-                opacity: pageTwo.down == true ? 1.0 : opacityDegree
-                color: JamiTheme.textColor
-            }
-
-            Rectangle {
-                id: pendingRequestCountRect
-
-                anchors.left: textInvElement.right
-                anchors.leftMargin: 4
-                anchors.verticalCenter: textInvElement.verticalCenter
-                anchors.verticalCenterOffset : -5
-
-                width: 12
-                height: 12
-
-                visible: pendingRequestCount > 0
-
-                Text {
-                    id: pendingRequestCountText
-
-                    anchors.centerIn: pendingRequestCountRect
-
-                    text: pendingRequestCount > 9 ? "···" : pendingRequestCount
-                    color: "white"
-                    font.pointSize: JamiTheme.indicatorFontSize
-                }
-                radius: 30
-                color: JamiTheme.notificationBlue
-            }
-
-            Rectangle {
-                id: markerTabTwo
-                width: buttonRectTwo.width
-                anchors.bottom: buttonRectTwo.bottom
-                height: 2
-                color: pageTwo.down == true ? JamiTheme.textColor : "transparent"
-            }
-
-            MouseArea {
-                anchors.fill: parent
-                hoverEnabled: true
-                onPressed: {
-                    selectTab(SidePanelTabBar.Requests)
-                }
-                onReleased: {
-                    buttonRectTwo.color = Qt.binding(function(){return JamiTheme.backgroundColor})
-                }
-                onEntered: {
-                    buttonRectTwo.color = Qt.binding(function(){return JamiTheme.hoverColor})
-                }
-                onExited: {
-                    buttonRectTwo.color = Qt.binding(function(){return JamiTheme.backgroundColor})
-                }
-            }
-
-            Shortcut {
-                sequence: "Ctrl+R"
-                context: Qt.ApplicationShortcut
-                enabled: buttonRectTwo.visible
-                onActivated: {
-                    selectTab(SidePanelTabBar.Requests)
-                }
-            }
-        }
+        tabBar: parent
+        labelText: JamiStrings.invitations
+        onSelected: selectTab(SidePanelTabBar.Requests)
+        badgeCount: pendingRequestCount
+        acceleratorSequence: "Ctrl+R"
     }
 }