diff --git a/assets/css/_bootstrap.scss b/assets/css/_bootstrap.scss
index 33ecee15f88f2acd7c0753f866405354fbf21ffa..89d914e69bff99ce2e94aac8b7c37c95bd2bbfb2 100644
--- a/assets/css/_bootstrap.scss
+++ b/assets/css/_bootstrap.scss
@@ -42,7 +42,7 @@
 @import "~bootstrap/scss/card";
 // @import "~bootstrap/scss/accordion";
 @import "~bootstrap/scss/breadcrumb";
-// @import "~bootstrap/scss/pagination";
+@import "~bootstrap/scss/pagination";
 @import "~bootstrap/scss/badge";
 @import "~bootstrap/scss/alert";
 // @import "~bootstrap/scss/progress";
diff --git a/assets/css/style.scss b/assets/css/style.scss
index fcfc15b451407dd517d6926fcf31982f405f7daa..f791e13f3b4ee2f1bee5f31168b85ffc84254ac2 100644
--- a/assets/css/style.scss
+++ b/assets/css/style.scss
@@ -30,10 +30,33 @@ $list-group-color: var(--txt-secondary-color);
 $list-group-active-bg: var(--bg-secondary-color);
 $list-group-active-color: var(--txt-secondary-color);
 $list-group-border-color: var(--border-color);
+$list-group-action-hover-color: var(--txt-secondary-color);
+$list-group-hover-bg: var(--bg-secondary-color);
 
 // Cards
 $card-bg: var(--bg-secondary-color);
 
+// Pagination
+$pagination-border-color: var(--border-color);
+$pagination-bg: var(--bg-menu-color);
+$pagination-color: var(--txt-secondary-color);
+
+$pagination-hover-border-color: $pagination-border-color;
+$pagination-hover-bg: var(--bg-secondary-color);
+$pagination-hover-color: var(--txt-secondary-color);
+
+$pagination-active-border-color: $pagination-border-color;
+$pagination-active-bg: var(--bg-secondary-color);
+$pagination-active-color: var(--txt-secondary-color);
+
+$pagination-focus-border-color: $pagination-hover-border-color;
+$pagination-focus-bg: $pagination-hover-bg;
+$pagination-focus-color: $pagination-hover-color;
+
+$pagination-disabled-border-color: $pagination-border-color;
+$pagination-disabled-bg: var(--bg-menu-color);
+$pagination-disabled-color: var(--txt-secondary-color);
+
 // Mark
 $mark-padding: 0.2em 0;
 $mark-bg: yellow;
diff --git a/components/btn/Pagination.vue b/components/btn/Pagination.vue
index 6dc4293d35e909db0896f1e6e8b3048b81996a75..a46580f7273492ece46f329f37f1777652c968ef 100644
--- a/components/btn/Pagination.vue
+++ b/components/btn/Pagination.vue
@@ -1,27 +1,48 @@
 <template>
-	<div class="text-center" v-if="arrayLength > pageSize">
-		<button
-			class="btn btn-secondary"
-			:class="{
-				'opacity-25': currentPage == 1
-			}"
-			@click="prevPage"
-			:disabled="currentPage == 1">
-			⟨
-		</button>
-		<span class="small px-2"
-			>{{ currentPage }} / {{ Math.ceil(arrayLength / pageSize) }}</span
-		>
-		<button
-			class="btn btn-secondary"
-			:class="{
-				'opacity-25': currentPage * pageSize >= arrayLength
-			}"
-			@click="nextPage"
-			:disabled="currentPage * pageSize >= arrayLength">
-			⟩
-		</button>
-	</div>
+	<nav :aria-label="$t('pagination.title')" v-if="nbPages > 1">
+		<ul class="pagination justify-content-center">
+			<li class="page-item" v-if="currentPage > 2 && nbPages > 3">
+				<a
+					class="page-link"
+					href="#"
+					:aria-label="$t('pagination.first')"
+					@click="firstPage($event)">
+					<span aria-hidden="true">1</span>
+				</a>
+			</li>
+			<li class="page-item disabled" v-if="currentPage > 3 && nbPages > 3">
+				<span class="page-link"><span aria-hidden="true">...</span></span>
+			</li>
+			<li
+				class="page-item"
+				v-for="index in listPagesUtiles"
+				:key="index"
+				:class="{ active: index == currentPage }">
+				<a
+					v-if="index != currentPage"
+					class="page-link"
+					href="#"
+					@click="goto(index, $event)"
+					>{{ index }}</a
+				>
+				<span v-else class="page-link">{{ index }}</span>
+			</li>
+			<li
+				class="page-item disabled"
+				v-if="currentPage < nbPages - 2 && nbPages > 3">
+				<span class="page-link"><span aria-hidden="true">...</span></span>
+			</li>
+			<li class="page-item" v-if="currentPage < nbPages - 1 && nbPages > 3">
+				<a
+					class="page-link"
+					href="#"
+					aria-label="$t('pagination.last')"
+					@click="lastPage($event)">
+					<span aria-hidden="true">{{ nbPages }}</span>
+				</a>
+			</li>
+		</ul>
+	</nav>
 </template>
 
 <script>
@@ -41,14 +62,49 @@ export default {
 		}
 	},
 	methods: {
-		nextPage: function () {
-			if (this.currentPage * this.pageSize < this.arrayLength)
-				this.$emit("update:currentPage", this.currentPage + 1)
+		goto(i, e) {
+			e.preventDefault()
+			this.$emit("update:currentPage", i)
 		},
-		prevPage: function () {
-			if (this.currentPage > 1)
-				this.$emit("update:currentPage", this.currentPage - 1)
+		firstPage: function (e) {
+			e.preventDefault()
+			this.$emit("update:currentPage", 1)
+		},
+		lastPage: function (e) {
+			e.preventDefault()
+			this.$emit("update:currentPage", this.nbPages)
+		}
+	},
+	computed: {
+		nbPages() {
+			return Math.ceil(this.arrayLength / this.pageSize)
+		},
+		listPagesUtiles() {
+			if (this.nbPages < 3) {
+				return [1, 2]
+			}
+
+			if (this.currentPage == 1) {
+				return [1, 2, 3]
+			}
+
+			if (this.currentPage == this.nbPages) {
+				return [this.nbPages - 2, this.nbPages - 1, this.nbPages]
+			}
+
+			return [this.currentPage - 1, this.currentPage, this.currentPage + 1]
 		}
 	}
 }
 </script>
+
+<style lang="scss" scoped>
+.pagination {
+	user-select: none;
+}
+
+.disabled,
+.active {
+	cursor: not-allowed;
+}
+</style>
diff --git a/components/certif/List.vue b/components/certif/List.vue
index df8189ae805c7f414e5bfba7bfef2a5077358f23..982ea728ebfac262c0cdc196d5b11175f6d5b594 100644
--- a/components/certif/List.vue
+++ b/components/certif/List.vue
@@ -4,14 +4,17 @@
 		<table class="table table-striped table-hover table-fixed sortable border">
 			<thead class="thead-light">
 				<tr>
-					<th class="p-0" @click="sort('uid')">
+					<th class="p-0" @click="sort('uid')" @keyup.enter="sort('uid')">
 						<BtnSort
 							:title="$t('membre.title')"
 							fieldName="uid"
 							:currentSort="currentSort"
 							:currentSortDir="currentSortDir" />
 					</th>
-					<th class="p-0 td-date" @click="sort('expires_on')">
+					<th
+						class="p-0 td-date"
+						@click="sort('expires_on')"
+						@keyup.enter="sort('expires_on')">
 						<BtnSort
 							:title="$t('expire')"
 							fieldName="expires_on"
@@ -24,6 +27,7 @@
 				<tr
 					v-for="certif in certifsTriees"
 					:key="certif.uid"
+					tabindex="0"
 					@click="
 						$router.push(
 							localePath({
@@ -31,6 +35,14 @@
 								query: { hash: certif.hash }
 							})
 						)
+					"
+					@keyup.enter="
+						$router.push(
+							localePath({
+								name: 'membre',
+								query: { hash: certif.hash }
+							})
+						)
 					">
 					<td class="py-1">
 						<div class="d-flex">
diff --git a/components/member/List.vue b/components/member/List.vue
index 1e2c213115d3ba0ec69e5500377c626a32ae85f4..429c0afe75f3caca6e5264a5961d008e5c04bf3f 100644
--- a/components/member/List.vue
+++ b/components/member/List.vue
@@ -8,8 +8,7 @@
 						class="p-0"
 						scope="col"
 						@click="sort('uid')"
-						@keyup.enter="sort('uid')"
-						@keyup.space="sort('uid')">
+						@keyup.enter="sort('uid')">
 						<BtnSort
 							fieldName="uid"
 							title="UID"
@@ -20,7 +19,8 @@
 						scope="col"
 						class="d-none d-lg-table-cell p-0"
 						v-if="['favoris', 'search'].includes(type)"
-						@click="sort('statut')">
+						@click="sort('statut')"
+						@keyup.enter="sort('statut')">
 						<BtnSort
 							fieldName="statut"
 							:title="$t('statut.title')"
@@ -31,7 +31,8 @@
 						scope="col"
 						class="td-quality d-none d-lg-table-cell p-0"
 						v-if="['favoris', 'search'].includes(type)"
-						@click="sort('quality')">
+						@click="sort('quality')"
+						@keyup.enter="sort('quality')">
 						<BtnSort
 							fieldName="quality"
 							:title="$t('membre.qualite.title')"
@@ -42,7 +43,8 @@
 						scope="col"
 						class="d-none d-xl-table-cell p-0"
 						v-if="['favoris', 'search'].includes(type)"
-						@click="sort('dispo')">
+						@click="sort('dispo')"
+						@keyup.enter="sort('dispo')">
 						<BtnSort
 							fieldName="dispo"
 							:title="$t('membre.dispo')"
@@ -53,6 +55,7 @@
 						scope="col"
 						class="td-date d-none d-sm-table-cell p-0"
 						@click="sort('date_membership')"
+						@keyup.enter="sort('date_membership')"
 						v-if="['adhesion', 'favoris', 'search'].includes(type)">
 						<BtnSort
 							fieldName="date_membership"
@@ -72,6 +75,7 @@
 							'd-md-table-cell': type != 'certif'
 						}"
 						@click="sort('date_certs')"
+						@keyup.enter="sort('date_certs')"
 						v-if="['certif', 'favoris', 'search'].includes(type)">
 						<BtnSort
 							fieldName="date_certs"
@@ -87,8 +91,13 @@
 				</tr>
 			</thead>
 			<tbody>
-				<tr v-for="member in membersSorted" :key="member.uid">
-					<td @click="redirect(member.hash)">
+				<tr
+					v-for="member in membersSorted"
+					:key="member.uid"
+					tabindex="0"
+					@click="redirect(member.hash)"
+					@keyup.enter="redirect(member.hash)">
+					<td>
 						<div class="d-flex">
 							<div
 								class="d-flex flex-column align-items-center justify-content-evenly flex-grow-1">
@@ -126,20 +135,17 @@
 					</td>
 					<td
 						class="d-none d-lg-table-cell"
-						v-if="['favoris', 'search'].includes(type)"
-						@click="redirect(member.hash)">
+						v-if="['favoris', 'search'].includes(type)">
 						<BadgeStatus :membre="member" />
 					</td>
 					<td
 						class="d-none d-lg-table-cell"
-						v-if="['favoris', 'search'].includes(type)"
-						@click="redirect(member.hash)">
+						v-if="['favoris', 'search'].includes(type)">
 						<BadgeQuality :quality="member.quality.ratio" />
 					</td>
 					<td
 						class="d-none d-xl-table-cell"
-						v-if="['favoris', 'search'].includes(type)"
-						@click="redirect(member.hash)">
+						v-if="['favoris', 'search'].includes(type)">
 						<BadgeDispo
 							:isDispo="member.minDatePassed"
 							:dateDispo="member.minDate"
@@ -147,8 +153,7 @@
 					</td>
 					<td
 						class="d-none d-sm-table-cell"
-						v-if="['adhesion', 'favoris', 'search'].includes(type)"
-						@click="redirect(member.hash)">
+						v-if="['adhesion', 'favoris', 'search'].includes(type)">
 						<BadgeDate :date="member.limitDate" styleDate="short" />
 					</td>
 					<td
@@ -157,8 +162,7 @@
 							'd-sm-table-cell': type == 'certif',
 							'd-md-table-cell': type != 'certif'
 						}"
-						v-if="['certif', 'favoris', 'search'].includes(type)"
-						@click="redirect(member.hash)">
+						v-if="['certif', 'favoris', 'search'].includes(type)">
 						<BadgeDate :date="member.certsLimit" styleDate="short" />
 					</td>
 					<td class="py-1" v-if="type == 'favoris'" style="width: 60px">
diff --git a/components/navigation/menu/Sidebar.vue b/components/navigation/menu/Sidebar.vue
index 5971ef74796ff56d82782303dd69457b65f8ae93..e05c5d83372ea8d002aa91f75def80af27fce5fa 100644
--- a/components/navigation/menu/Sidebar.vue
+++ b/components/navigation/menu/Sidebar.vue
@@ -3,7 +3,7 @@
 		<div class="mb-4">
 			<nuxt-link
 				@click.native="
-					if (sreenwidth < 1200) {
+					if (screenwidth < 1200) {
 						toggleMenu()
 					}
 				"
@@ -41,7 +41,12 @@
 		<div class="py-3 text-center">
 			<button
 				class="btn btn-secondary btn-sm"
-				@click="$router.push(localePath('a-propos'))">
+				@click="
+					if (screenwidth < 1200) {
+						toggleMenu()
+					}
+					$router.push(localePath('a-propos'))
+				">
 				v{{ $config.clientVersion }} | {{ $t("apropos.title") }}
 			</button>
 		</div>
@@ -55,7 +60,7 @@ import { VERSION } from "@/graphql/queries.js"
 export default {
 	data() {
 		return {
-			sreenwidth: 0
+			screenwidth: 0
 		}
 	},
 	props: {
@@ -66,7 +71,7 @@ export default {
 			this.$emit("toggleMenu")
 		},
 		onResize() {
-			this.sreenwidth = window.screen.width
+			this.screenwidth = window.innerWidth
 		}
 	},
 	apollo: {
@@ -78,7 +83,7 @@ export default {
 		}
 	},
 	mounted() {
-		this.sreenwidth = window.screen.width
+		this.screenwidth = window.innerWidth
 		this.$nextTick(function () {
 			this.onResize()
 		})
diff --git a/pages/previsions/index.vue b/pages/previsions/index.vue
index b9c9c58f9ac6698bb35b0058f6efe3fdc133419c..00c88502c2e84076e36e0c4085359e745e4e35a3 100644
--- a/pages/previsions/index.vue
+++ b/pages/previsions/index.vue
@@ -51,6 +51,7 @@
 										<tr
 											v-for="forecast in wwResult.forecastsByNames"
 											:key="forecast.member.uid"
+											tabindex="0"
 											@click="
 												$router.push(
 													localePath({
@@ -58,9 +59,18 @@
 														query: { hash: forecast.member.hash }
 													})
 												)
+											"
+											@keyup.enter="
+												$router.push(
+													localePath({
+														name: 'membre',
+														query: { hash: forecast.member.hash }
+													})
+												)
 											">
 											<td class="td-uid">
-												<span class="text-truncate mw-100 d-inline-block">
+												<span
+													class="text-truncate mw-100 d-inline-block txt-secondary">
 													<span
 														v-if="
 															$favourites.list.includes(forecast.member.uid)
@@ -75,7 +85,7 @@
 													v-for="date in forecast.forecasts"
 													:key="date.date">
 													<div
-														class="text-center"
+														class="text-center txt-secondary"
 														v-if="date.date < 9999999999">
 														{{ $d(new Date(date.date * 1000), "short") }}
 														{{ $t("time.a") }}&nbsp;{{
@@ -105,17 +115,19 @@
 											v-for="forecast in wwResult.forecastsByDates"
 											:key="forecast.date">
 											<td class="text-center" v-if="forecast.date < 9999999999">
-												{{ $d(new Date(forecast.date * 1000), "short") }}
-												{{ $t("time.a") }}&nbsp;{{
-													$d(new Date(forecast.date * 1000), "hour").replace(
-														" ",
-														"&nbsp;"
-													)
-												}}
+												<span class="txt-secondary">
+													{{ $d(new Date(forecast.date * 1000), "short") }}
+													{{ $t("time.a") }}&nbsp;{{
+														$d(new Date(forecast.date * 1000), "hour").replace(
+															" ",
+															"&nbsp;"
+														)
+													}}
+												</span>
 											</td>
 											<td v-else>N/A</td>
 											<td class="p-0 td-uid">
-												<div class="list-group">
+												<div class="list-group rounded-0">
 													<nuxt-link
 														class="list-group-item list-group-item-action border-0 d-flex justify-content-between align-items-center"
 														:to="
@@ -276,6 +288,11 @@ export default {
 </script>
 
 <style lang="scss" scoped>
+.table-hover > tbody > tr:focus > * {
+	--bs-table-accent-bg: var(--bs-table-hover-bg);
+	color: var(--bs-table-hover-color);
+}
+
 .p-date,
 .list-group-item {
 	flex-direction: column;
@@ -285,15 +302,6 @@ export default {
 	}
 }
 
-.list-group-item {
-	background: transparent;
-
-	&:hover {
-		background: var(--bg-secondary-color);
-		color: var(--txt-primary-color);
-	}
-}
-
 .td-uid {
 	width: 50%;
 }
diff --git a/plugins/favourites.js b/plugins/favourites.js
index 766b4c538b09f4e0aae2805833590ed3b55ccf7d..36616e66eab13c54231d2a9435e7efa7608c5015 100644
--- a/plugins/favourites.js
+++ b/plugins/favourites.js
@@ -6,6 +6,7 @@ export default (context, inject) => {
 		: []
 
 	let toggleFavourite = (uid, e) => {
+		e.stopPropagation()
 		if (!context.$favourites.list.includes(uid)) {
 			context.$favourites.list.push(uid)
 		} else {