diff --git a/web/src/constants.js b/web/src/constants.js
new file mode 100644
index 0000000000000000000000000000000000000000..de75b5da9c8620c0305caf0433f35b5e5d9058e2
--- /dev/null
+++ b/web/src/constants.js
@@ -0,0 +1,4 @@
+export const DEFAULT_PER_ROW = 4;
+export const MIN_PER_ROW = 2;
+export const MAX_PER_ROW = 10;
+export const FREQUENTLY_USED_ROWS = 3;
diff --git a/web/src/frequently-used.js b/web/src/frequently-used.js
index d35f6a913cb7a4dd8ca89e47a59db9d0f9268bcd..4aa994d3f344291c6a4213edb373bd41fd3a43a3 100644
--- a/web/src/frequently-used.js
+++ b/web/src/frequently-used.js
@@ -14,6 +14,8 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
+import { MAX_PER_ROW, FREQUENTLY_USED_ROWS } from "./constants.js"
+
 const FREQUENTLY_USED_STORAGE_KEY = 'mauFrequentlyUsedStickerIDs'
 const FREQUENTLY_USED_STORAGE_CACHE_KEY = 'mauFrequentlyUsedStickerCache'
 
@@ -44,7 +46,7 @@ export const add = (id) => {
 	setFrequentlyUsedStorage(FREQUENTLY_USED_COPY)
 }
 
-export const get = (limit = 16) => {
+export const get = (limit = FREQUENTLY_USED_ROWS * MAX_PER_ROW) => {
 	if (FREQUENTLY_USED_SORTED === null) {
 		FREQUENTLY_USED_SORTED = Object.entries(FREQUENTLY_USED || {})
 			.sort(sortFrequentlyUsedEntries)
diff --git a/web/src/index.js b/web/src/index.js
index 8ef30c99114de8d18a2d47a3296ba19a59ff568e..573b6cd8a0e8ea6aeafcec0d2c3c5000bde2821d 100644
--- a/web/src/index.js
+++ b/web/src/index.js
@@ -21,6 +21,7 @@ import {giphyIsEnabled, GiphySearchTab, setGiphyAPIKey} from "./giphy.js"
 import * as widgetAPI from "./widget-api.js"
 import * as frequent from "./frequently-used.js"
 import * as userSettings from "./user-settings.js"
+import * as constants from "./constants.js"
 
 // The base URL for fetching packs. The app will first fetch ${PACK_BASE_URL}/index.json,
 // then ${PACK_BASE_URL}/${packFile} for each packFile in the packs object of the index.json file.
@@ -71,11 +72,14 @@ const sanitizeString = s => s.toLowerCase().trim()
 class App extends Component {
 	constructor(props) {
 		super(props)
+
+		const stickersPerRow = +(localStorage.mauStickersPerRow ?? constants.DEFAULT_PER_ROW)
+
 		this.defaultTheme = getUrlParameter("theme")
 		this.state = {
 			...defaultState,
 			...defaultSearchState,
-			stickersPerRow: parseInt(localStorage.mauStickersPerRow || "4"),
+			stickersPerRow,
 			theme: localStorage.mauStickerThemeOverride || this.defaultTheme,
 			frequentlyUsed: makeFrequentlyUsedState(),
 			userSettings: {
@@ -162,12 +166,10 @@ class App extends Component {
 		body.classList = `theme-${theme}`
 	}
 
-	setStickersPerRow(val) {
-		localStorage.mauStickersPerRow = val
+	setStickersPerRow(stickersPerRow) {
+		localStorage.mauStickersPerRow = stickersPerRow
 		document.documentElement.style.setProperty("--stickers-per-row", localStorage.mauStickersPerRow)
-		this.setState({
-			stickersPerRow: val,
-		})
+		this.setState({ stickersPerRow })
 		this.packListRef.scrollTop = this.packListRef.scrollHeight
 	}
 
@@ -408,7 +410,10 @@ const Settings = ({app}) => html`
 			<button onClick=${app.clearFrequentlyUsed}>Clear frequently used</button>
 			<div>
 				<label for="stickers-per-row">Stickers per row: ${app.state.stickersPerRow}</label>
-				<input type="range" min=2 max=10 id="stickers-per-row" id="stickers-per-row"
+				<input type="range"
+					min=${constants.MIN_PER_ROW}
+					max=${constants.MAX_PER_ROW}
+					id="stickers-per-row"
 					value=${app.state.stickersPerRow}
 					onInput=${evt => app.setStickersPerRow(evt.target.value)}/>
 			</div>