diff --git a/ui/src/Components/Pagination/index.js b/ui/src/Components/Pagination/index.js
new file mode 100644
index 000000000..c654eedfd
--- /dev/null
+++ b/ui/src/Components/Pagination/index.js
@@ -0,0 +1,89 @@
+import React, { Component } from "react";
+import PropTypes from "prop-types";
+
+import { HotKeys } from "react-hotkeys";
+
+import Pagination from "react-js-pagination";
+
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faAngleLeft } from "@fortawesome/free-solid-svg-icons/faAngleLeft";
+import { faAngleRight } from "@fortawesome/free-solid-svg-icons/faAngleRight";
+import { faAngleDoubleLeft } from "@fortawesome/free-solid-svg-icons/faAngleDoubleLeft";
+import { faAngleDoubleRight } from "@fortawesome/free-solid-svg-icons/faAngleDoubleRight";
+
+class PageSelect extends Component {
+ static propTypes = {
+ totalPages: PropTypes.number.isRequired,
+ activePage: PropTypes.number.isRequired,
+ maxPerPage: PropTypes.number.isRequired,
+ totalItemsCount: PropTypes.number.isRequired,
+ setPageCallback: PropTypes.func.isRequired
+ };
+
+ constructor(props) {
+ super(props);
+ this.HotKeysRef = React.createRef();
+ }
+
+ onPageUp = () => {
+ const { setPageCallback, activePage, totalPages } = this.props;
+ setPageCallback(Math.min(activePage + 1, totalPages));
+ };
+
+ onPageDown = () => {
+ const { setPageCallback, activePage } = this.props;
+ setPageCallback(Math.max(activePage - 1, 1));
+ };
+
+ componentDidMount() {
+ this.HotKeysRef.current.focus();
+ }
+
+ render() {
+ const {
+ totalItemsCount,
+ maxPerPage,
+ activePage,
+ setPageCallback
+ } = this.props;
+
+ return (
+
+ {totalItemsCount > maxPerPage ? (
+
+
}
+ nextPageText={
}
+ firstPageText={
}
+ lastPageText={
}
+ />
+
+ ) : null}
+
+ );
+ }
+}
+
+export { PageSelect };
diff --git a/ui/src/Components/Pagination/index.test.js b/ui/src/Components/Pagination/index.test.js
new file mode 100644
index 000000000..3c42f9313
--- /dev/null
+++ b/ui/src/Components/Pagination/index.test.js
@@ -0,0 +1,51 @@
+import React from "react";
+
+import { mount } from "enzyme";
+
+import { PressKey } from "__mocks__/KeyPress";
+import { PageSelect } from ".";
+
+describe("", () => {
+ it("calls setPageCallback on arrow key press", () => {
+ const setPageCallback = jest.fn();
+
+ const tree = mount(
+
+ );
+ tree.simulate("focus");
+
+ setPageCallback.mockImplementation(val =>
+ tree.setProps({ activePage: val })
+ );
+
+ PressKey(tree, "ArrowRight", 39);
+ expect(setPageCallback).toHaveBeenLastCalledWith(2);
+
+ PressKey(tree, "ArrowRight", 39);
+ expect(setPageCallback).toHaveBeenLastCalledWith(3);
+
+ PressKey(tree, "ArrowRight", 39);
+ expect(setPageCallback).toHaveBeenLastCalledWith(4);
+
+ PressKey(tree, "ArrowRight", 39);
+ expect(setPageCallback).toHaveBeenLastCalledWith(4);
+
+ PressKey(tree, "ArrowLeft", 37);
+ expect(setPageCallback).toHaveBeenLastCalledWith(3);
+
+ PressKey(tree, "ArrowLeft", 37);
+ expect(setPageCallback).toHaveBeenLastCalledWith(2);
+
+ PressKey(tree, "ArrowLeft", 37);
+ expect(setPageCallback).toHaveBeenLastCalledWith(1);
+
+ PressKey(tree, "ArrowLeft", 37);
+ expect(setPageCallback).toHaveBeenLastCalledWith(1);
+ });
+});
diff --git a/ui/src/Styles/Components/Pagination.scss b/ui/src/Styles/Components/Pagination.scss
new file mode 100644
index 000000000..550e68f80
--- /dev/null
+++ b/ui/src/Styles/Components/Pagination.scss
@@ -0,0 +1,3 @@
+.components-pagination:focus {
+ outline: none;
+}
diff --git a/ui/src/Styles/DarkTheme.scss b/ui/src/Styles/DarkTheme.scss
index 0f0b67961..066614883 100644
--- a/ui/src/Styles/DarkTheme.scss
+++ b/ui/src/Styles/DarkTheme.scss
@@ -122,6 +122,7 @@ $color-default: #708090;
@import "Styles/Components/MountFade";
@import "Styles/Components/NavBarSlide";
@import "Styles/Components/SilenceModal";
+@import "Styles/Components/Pagination";
.badge,
.modal-content {
diff --git a/ui/src/Styles/LightTheme.scss b/ui/src/Styles/LightTheme.scss
index c276a293e..17db130f2 100644
--- a/ui/src/Styles/LightTheme.scss
+++ b/ui/src/Styles/LightTheme.scss
@@ -105,6 +105,7 @@ $color-default: #708090;
@import "Styles/Components/MountFade";
@import "Styles/Components/NavBarSlide";
@import "Styles/Components/SilenceModal";
+@import "Styles/Components/Pagination";
a {
color: $link-color;
diff --git a/ui/src/__mocks__/KeyPress.js b/ui/src/__mocks__/KeyPress.js
new file mode 100644
index 000000000..c4652b0b1
--- /dev/null
+++ b/ui/src/__mocks__/KeyPress.js
@@ -0,0 +1,6 @@
+const PressKey = (tree, key, code) => {
+ tree.simulate("keyDown", { key: key, keyCode: code, which: code });
+ tree.simulate("keyUp", { key: key, keyCode: code, which: code });
+};
+
+export { PressKey };