diff --git a/package.json b/package.json
index e6d0afff35..fce3b2a503 100644
--- a/package.json
+++ b/package.json
@@ -36,7 +36,8 @@
 		"vue": "^2.5.16",
 		"vue-click-outside": "^1.0.7",
 		"vue-multiselect": "^2.1.0",
-		"vue2-datepicker": "^2.4.1"
+		"vue2-datepicker": "^2.4.1",
+		"nextcloud-axios": "^0.1.2"
 	},
 	"engines": {
 		"node": ">=10.0.0"
diff --git a/src/components/Avatar/Avatar.vue b/src/components/Avatar/Avatar.vue
new file mode 100644
index 0000000000..6d4678dc09
--- /dev/null
+++ b/src/components/Avatar/Avatar.vue
@@ -0,0 +1,176 @@
+<!--
+  - @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
+  -
+  - @author Julius Härtl <jus@bitgrid.net>
+  -
+  - @license GNU AGPL version 3 or any later version
+  -
+  - This program is free software: you can redistribute it and/or modify
+  - it under the terms of the GNU Affero 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 Affero General Public License for more details.
+  -
+  - You should have received a copy of the GNU Affero General Public License
+  - along with this program. If not, see <http://www.gnu.org/licenses/>.
+  -
+  -->
+
+<template>
+	<div v-tooltip="displayName" v-click-outside="closeMenu"
+		:class="{ 'icon-loading': loading, 'unknown': unknown }"
+		:style="{width: size + 'px', height: size + 'px'}"
+		class="avatardiv popovermenu-wrapper" @click="toggleMenu">
+		<img v-if="!loading && !unknown" :src="avatarUrlLoaded">
+		<div v-if="unknown" class="unknown">?</div>
+		<div v-show="openedMenu" class="popovermenu">
+			<popover-menu :is-open="openedMenu" :menu="menu" />
+		</div>
+	</div>
+</template>
+
+<script>
+
+/* global OC oc_userconfig */
+
+import { VTooltip } from 'v-tooltip'
+import { PopoverMenu } from '../PopoverMenu'
+import ClickOutside from 'vue-click-outside'
+import axios from 'nextcloud-axios'
+
+export default {
+	name: 'Avatar',
+	directives: {
+		tooltip: VTooltip,
+		ClickOutside: ClickOutside
+	},
+	components: {
+		PopoverMenu
+	},
+	props: {
+		url: {
+			type: String,
+			default: undefined
+		},
+		user: {
+			type: String,
+			default: undefined
+		},
+		displayName: {
+			type: String,
+			default: undefined
+		},
+		size: {
+			type: Number,
+			default: 32
+		}
+	},
+	data() {
+		return {
+			actions: [],
+			avatarUrlLoaded: null,
+			unknown: false,
+			loading: true,
+			openedMenu: false
+		}
+	},
+	computed: {
+		menu() {
+			return this.actions.map((item) => {
+				return {
+					href: item.hyperlink,
+					icon: item.icon,
+					text: item.title
+				}
+			})
+		}
+	},
+	mounted() {
+		let avatarUrl = OC.generateUrl(
+			'/avatar/{user}/{size}',
+			{
+				user: this.user,
+				size: Math.ceil(this.size * window.devicePixelRatio)
+			})
+		if (this.user === OC.getCurrentUser().uid) {
+			avatarUrl += '?v=' + oc_userconfig.avatar.version
+		}
+		if (typeof this.url !== 'undefined') {
+			avatarUrl = this.url
+		}
+
+		let img = new Image()
+		img.onload = () => {
+			this.avatarUrlLoaded = avatarUrl
+			this.loading = false
+		}
+		img.onerror = () => {
+			this.unknown = true
+			this.loading = false
+		}
+		img.src = avatarUrl
+	},
+	methods: {
+		toggleMenu() {
+			if (this.user === OC.getCurrentUser().uid || this.unknown || this.url) {
+				return
+			}
+			this.openedMenu = !this.openedMenu
+			if (this.openedMenu) {
+				this.fetchContactsMenu()
+			}
+		},
+		closeMenu() {
+			this.openedMenu = false
+		},
+		fetchContactsMenu() {
+			axios.post(OC.generateUrl('contactsmenu/findOne'), 'shareType=0&shareWith=' + this.user).then((response) => {
+				this.actions = [response.data.topAction].concat(response.data.actions)
+			}).catch(() => {
+				this.openedMenu = false
+			})
+		}
+	}
+}
+</script>
+
+<style scoped>
+	.avatardiv {
+		display: inline-block;
+	}
+
+	.avatardiv.unknown {
+		background-color: var(--color-text-maxcontrast);
+		position: relative;
+	}
+
+	.avatardiv > .unknown {
+		position: absolute;
+		color: var(--color-main-background);
+		width: 100%;
+		text-align: center;
+		font-size: 14pt;
+		display: block;
+		top: 18%;
+		left: 0;
+	}
+
+	.avatardiv img {
+		width: 100%;
+		height: 100%;
+	}
+
+	.popovermenu-wrapper {
+		position: relative;
+		display: inline-block;
+	}
+
+	.popovermenu {
+		display: block;
+		margin: 0;
+	}
+</style>
diff --git a/src/components/Avatar/index.js b/src/components/Avatar/index.js
new file mode 100644
index 0000000000..87d4bf91da
--- /dev/null
+++ b/src/components/Avatar/index.js
@@ -0,0 +1,26 @@
+/**
+ * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+import Avatar from './Avatar'
+
+export default Avatar
+export { Avatar }
diff --git a/src/components/PopoverMenu/PopoverMenuItem.vue b/src/components/PopoverMenu/PopoverMenuItem.vue
index d70cfc4884..d70a78f051 100644
--- a/src/components/PopoverMenu/PopoverMenuItem.vue
+++ b/src/components/PopoverMenu/PopoverMenuItem.vue
@@ -26,7 +26,8 @@
 		<a v-if="item.href" :href="(item.href) ? item.href : '#' "
 			:target="(item.target) ? item.target : '' "
 			rel="noreferrer noopener" @click="action">
-			<span :class="item.icon" />
+			<span v-if="!iconIsUrl" :class="item.icon" />
+			<img v-else :src="item.icon">
 			<span v-if="item.text">{{ item.text }}</span>
 			<p v-else-if="item.longtext">{{ item.longtext }}</p>
 		</a>
@@ -100,6 +101,15 @@ export default {
 			return this.item.key
 				? this.item.key
 				: Math.round(Math.random() * 16 * 1000000).toString(16)
+		},
+		iconIsUrl() {
+			try {
+				// eslint-disable-next-line no-new
+				new URL(this.item.icon)
+				return true
+			} catch (_) {
+				return false
+			}
 		}
 	},
 	methods: {
diff --git a/src/components/index.js b/src/components/index.js
index eb7857afdf..e00cd1adca 100644
--- a/src/components/index.js
+++ b/src/components/index.js
@@ -24,10 +24,12 @@ import AppNavigation from './AppNavigation'
 import PopoverMenu from './PopoverMenu'
 import DatetimePicker from './DatetimePicker'
 import Multiselect from './Multiselect'
+import Avatar from './Avatar'
 
 export {
 	AppNavigation,
 	PopoverMenu,
 	DatetimePicker,
-	Multiselect
+	Multiselect,
+	Avatar
 }