diff --git a/web/src/app/Connection.js b/web/src/app/Connection.js
index 9e479f94..914fcf45 100644
--- a/web/src/app/Connection.js
+++ b/web/src/app/Connection.js
@@ -1,6 +1,6 @@
 import {shortTopicUrl, topicUrlWs, topicUrlWsWithSince} from "./utils";
 
-const retryBackoffSeconds = [5, 10, 15, 20, 30, 45, 60, 120];
+const retryBackoffSeconds = [5, 10, 15, 20, 30, 45];
 
 class Connection {
     constructor(subscriptionId, baseUrl, topic, since, onNotification) {
diff --git a/web/src/components/ActionBar.js b/web/src/components/ActionBar.js
new file mode 100644
index 00000000..7ecce8e4
--- /dev/null
+++ b/web/src/components/ActionBar.js
@@ -0,0 +1,36 @@
+import AppBar from "@mui/material/AppBar";
+import Navigation from "./Navigation";
+import Toolbar from "@mui/material/Toolbar";
+import IconButton from "@mui/material/IconButton";
+import MenuIcon from "@mui/icons-material/Menu";
+import Typography from "@mui/material/Typography";
+import IconSubscribeSettings from "./IconSubscribeSettings";
+import * as React from "react";
+
+const ActionBar = (props) => {
+    const title = (props.selectedSubscription !== null)
+        ? props.selectedSubscription.shortUrl()
+        : "ntfy";
+    return (
+        <AppBar position="fixed" sx={{ width: { sm: `calc(100% - ${Navigation.width}px)` }, ml: { sm: `${Navigation.width}px` } }}>
+            <Toolbar sx={{pr: '24px'}}>
+                <IconButton
+                    color="inherit"
+                    edge="start"
+                    onClick={props.onMobileDrawerToggle}
+                    sx={{ mr: 2, display: { sm: 'none' } }}
+                >
+                    <MenuIcon />
+                </IconButton>
+                <Typography variant="h6" noWrap component="div" sx={{ flexGrow: 1 }}>{title}</Typography>
+                {props.selectedSubscription !== null && <IconSubscribeSettings
+                    subscription={props.selectedSubscription}
+                    onClearAll={props.onClearAll}
+                    onUnsubscribe={props.onUnsubscribe}
+                />}
+            </Toolbar>
+        </AppBar>
+    );
+};
+
+export default ActionBar;
diff --git a/web/src/components/App.js b/web/src/components/App.js
index 63055aa3..51097833 100644
--- a/web/src/components/App.js
+++ b/web/src/components/App.js
@@ -1,161 +1,17 @@
 import * as React from 'react';
 import {useEffect, useState} from 'react';
-import Typography from '@mui/material/Typography';
 import Box from '@mui/material/Box';
 import {ThemeProvider} from '@mui/material/styles';
 import CssBaseline from '@mui/material/CssBaseline';
-import Drawer from '@mui/material/Drawer';
-import AppBar from '@mui/material/AppBar';
 import Toolbar from '@mui/material/Toolbar';
-import ChatBubbleOutlineIcon from '@mui/icons-material/ChatBubbleOutline';
-import List from '@mui/material/List';
-import Divider from '@mui/material/Divider';
-import IconButton from '@mui/material/IconButton';
-import MenuIcon from '@mui/icons-material/Menu';
-import ListItemIcon from "@mui/material/ListItemIcon";
-import ListItemText from "@mui/material/ListItemText";
-import ListItemButton from "@mui/material/ListItemButton";
-import SettingsIcon from "@mui/icons-material/Settings";
-import AddIcon from "@mui/icons-material/Add";
-import SubscribeDialog from "./SubscribeDialog";
 import NotificationList from "./NotificationList";
-import IconSubscribeSettings from "./IconSubscribeSettings";
 import theme from "./theme";
 import api from "../app/Api";
 import repository from "../app/Repository";
 import connectionManager from "../app/ConnectionManager";
 import Subscriptions from "../app/Subscriptions";
-
-const drawerWidth = 240;
-
-const NavSubscriptionList = (props) => {
-    const subscriptions = props.subscriptions;
-    return (
-        <>
-            {subscriptions.map((id, subscription) =>
-                <NavSubscriptionItem
-                    key={id}
-                    subscription={subscription}
-                    selected={props.selectedSubscription && props.selectedSubscription.id === id}
-                    onClick={() => props.onSubscriptionClick(id)}
-                />)
-            }
-        </>
-    );
-}
-
-const NavSubscriptionItem = (props) => {
-    const subscription = props.subscription;
-    return (
-        <ListItemButton onClick={props.onClick} selected={props.selected}>
-            <ListItemIcon><ChatBubbleOutlineIcon /></ListItemIcon>
-            <ListItemText primary={subscription.shortUrl()}/>
-        </ListItemButton>
-    );
-}
-
-const NavList = (props) => {
-    const [subscribeDialogOpen, setSubscribeDialogOpen] = useState(false);
-    const handleSubscribeSubmit = (subscription) => {
-        setSubscribeDialogOpen(false);
-        props.onSubscribeSubmit(subscription);
-    }
-    return (
-        <>
-            <Toolbar />
-            <Divider />
-            <List component="nav">
-                <NavSubscriptionList
-                    subscriptions={props.subscriptions}
-                    selectedSubscription={props.selectedSubscription}
-                    onSubscriptionClick={props.onSubscriptionClick}
-                />
-                <Divider sx={{ my: 1 }} />
-                <ListItemButton>
-                    <ListItemIcon>
-                        <SettingsIcon />
-                    </ListItemIcon>
-                    <ListItemText primary="Settings" />
-                </ListItemButton>
-                <ListItemButton onClick={() => setSubscribeDialogOpen(true)}>
-                    <ListItemIcon>
-                        <AddIcon />
-                    </ListItemIcon>
-                    <ListItemText primary="Add subscription" />
-                </ListItemButton>
-            </List>
-            <SubscribeDialog
-                open={subscribeDialogOpen}
-                onCancel={() => setSubscribeDialogOpen(false)}
-                onSubmit={handleSubscribeSubmit}
-            />
-        </>
-    );
-};
-
-const ActionBar = (props) => {
-    const title = (props.selectedSubscription !== null)
-        ? props.selectedSubscription.shortUrl()
-        : "ntfy";
-    return (
-        <AppBar position="fixed" sx={{ width: { sm: `calc(100% - ${drawerWidth}px)` }, ml: { sm: `${drawerWidth}px` } }}>
-            <Toolbar sx={{pr: '24px'}}>
-                <IconButton
-                    color="inherit"
-                    edge="start"
-                    onClick={props.onMobileDrawerToggle}
-                    sx={{ mr: 2, display: { sm: 'none' } }}
-                >
-                    <MenuIcon />
-                </IconButton>
-                <Typography variant="h6" noWrap component="div" sx={{ flexGrow: 1 }}>{title}</Typography>
-                {props.selectedSubscription !== null && <IconSubscribeSettings
-                    subscription={props.selectedSubscription}
-                    onClearAll={props.onClearAll}
-                    onUnsubscribe={props.onUnsubscribe}
-                />}
-            </Toolbar>
-        </AppBar>
-    );
-};
-
-const Sidebar = (props) => {
-    const navigationList =
-        <NavList
-            subscriptions={props.subscriptions}
-            selectedSubscription={props.selectedSubscription}
-            onSubscriptionClick={props.onSubscriptionClick}
-            onSubscribeSubmit={props.onSubscribeSubmit}
-        />;
-    return (
-        <>
-            {/* Mobile drawer; only shown if menu icon clicked (mobile open) and display is small */}
-            <Drawer
-                variant="temporary"
-                open={props.mobileDrawerOpen}
-                onClose={props.onMobileDrawerToggle}
-                ModalProps={{ keepMounted: true }} // Better open performance on mobile.
-                sx={{
-                    display: { xs: 'block', sm: 'none' },
-                    '& .MuiDrawer-paper': { boxSizing: 'border-box', width: drawerWidth },
-                }}
-            >
-                {navigationList}
-            </Drawer>
-            {/* Big screen drawer; persistent, shown if screen is big */}
-            <Drawer
-                open
-                variant="permanent"
-                sx={{
-                    display: { xs: 'none', sm: 'block' },
-                    '& .MuiDrawer-paper': { boxSizing: 'border-box', width: drawerWidth },
-                }}
-            >
-                {navigationList}
-            </Drawer>
-        </>
-    );
-};
+import Navigation from "./Navigation";
+import ActionBar from "./ActionBar";
 
 const App = () => {
     console.log(`[App] Rendering main view`);
@@ -222,8 +78,8 @@ const App = () => {
                     onUnsubscribe={handleUnsubscribe}
                     onMobileDrawerToggle={() => setMobileDrawerOpen(!mobileDrawerOpen)}
                 />
-                <Box component="nav" sx={{width: {sm: drawerWidth}, flexShrink: {sm: 0}}}>
-                    <Sidebar
+                <Box component="nav" sx={{width: {sm: Navigation.width}, flexShrink: {sm: 0}}}>
+                    <Navigation
                         subscriptions={subscriptions}
                         selectedSubscription={selectedSubscription}
                         mobileDrawerOpen={mobileDrawerOpen}
@@ -237,7 +93,7 @@ const App = () => {
                     sx={{
                         flexGrow: 1,
                         p: 3,
-                        width: {sm: `calc(100% - ${drawerWidth}px)`},
+                        width: {sm: `calc(100% - ${Navigation.width}px)`},
                         height: '100vh',
                         overflow: 'auto',
                         backgroundColor: (theme) => theme.palette.mode === 'light' ? theme.palette.grey[100] : theme.palette.grey[900]
diff --git a/web/src/components/Navigation.js b/web/src/components/Navigation.js
new file mode 100644
index 00000000..5d8b6e7e
--- /dev/null
+++ b/web/src/components/Navigation.js
@@ -0,0 +1,121 @@
+import Drawer from "@mui/material/Drawer";
+import * as React from "react";
+import ListItemButton from "@mui/material/ListItemButton";
+import ListItemIcon from "@mui/material/ListItemIcon";
+import ChatBubbleOutlineIcon from "@mui/icons-material/ChatBubbleOutline";
+import ListItemText from "@mui/material/ListItemText";
+import {useState} from "react";
+import Toolbar from "@mui/material/Toolbar";
+import Divider from "@mui/material/Divider";
+import List from "@mui/material/List";
+import SettingsIcon from "@mui/icons-material/Settings";
+import AddIcon from "@mui/icons-material/Add";
+import SubscribeDialog from "./SubscribeDialog";
+
+const navWidth = 240;
+
+const Navigation = (props) => {
+    const navigationList =
+        <NavList
+            subscriptions={props.subscriptions}
+            selectedSubscription={props.selectedSubscription}
+            onSubscriptionClick={props.onSubscriptionClick}
+            onSubscribeSubmit={props.onSubscribeSubmit}
+        />;
+    return (
+        <>
+            {/* Mobile drawer; only shown if menu icon clicked (mobile open) and display is small */}
+            <Drawer
+                variant="temporary"
+                open={props.mobileDrawerOpen}
+                onClose={props.onMobileDrawerToggle}
+                ModalProps={{ keepMounted: true }} // Better open performance on mobile.
+                sx={{
+                    display: { xs: 'block', sm: 'none' },
+                    '& .MuiDrawer-paper': { boxSizing: 'border-box', width: navWidth },
+                }}
+            >
+                {navigationList}
+            </Drawer>
+            {/* Big screen drawer; persistent, shown if screen is big */}
+            <Drawer
+                open
+                variant="permanent"
+                sx={{
+                    display: { xs: 'none', sm: 'block' },
+                    '& .MuiDrawer-paper': { boxSizing: 'border-box', width: navWidth },
+                }}
+            >
+                {navigationList}
+            </Drawer>
+        </>
+    );
+};
+Navigation.width = navWidth;
+
+const NavList = (props) => {
+    const [subscribeDialogOpen, setSubscribeDialogOpen] = useState(false);
+    const handleSubscribeSubmit = (subscription) => {
+        setSubscribeDialogOpen(false);
+        props.onSubscribeSubmit(subscription);
+    }
+    return (
+        <>
+            <Toolbar />
+            {props.subscriptions.size() > 0 &&
+                <Divider />}
+            <List component="nav">
+                <NavSubscriptionList
+                    subscriptions={props.subscriptions}
+                    selectedSubscription={props.selectedSubscription}
+                    onSubscriptionClick={props.onSubscriptionClick}
+                />
+                <Divider sx={{ my: 1 }} />
+                <ListItemButton>
+                    <ListItemIcon>
+                        <SettingsIcon />
+                    </ListItemIcon>
+                    <ListItemText primary="Settings" />
+                </ListItemButton>
+                <ListItemButton onClick={() => setSubscribeDialogOpen(true)}>
+                    <ListItemIcon>
+                        <AddIcon />
+                    </ListItemIcon>
+                    <ListItemText primary="Add subscription" />
+                </ListItemButton>
+            </List>
+            <SubscribeDialog
+                open={subscribeDialogOpen}
+                onCancel={() => setSubscribeDialogOpen(false)}
+                onSubmit={handleSubscribeSubmit}
+            />
+        </>
+    );
+};
+const NavSubscriptionList = (props) => {
+    const subscriptions = props.subscriptions;
+    return (
+        <>
+            {subscriptions.map((id, subscription) =>
+                <NavSubscriptionItem
+                    key={id}
+                    subscription={subscription}
+                    selected={props.selectedSubscription && props.selectedSubscription.id === id}
+                    onClick={() => props.onSubscriptionClick(id)}
+                />)
+            }
+        </>
+    );
+}
+
+const NavSubscriptionItem = (props) => {
+    const subscription = props.subscription;
+    return (
+        <ListItemButton onClick={props.onClick} selected={props.selected}>
+            <ListItemIcon><ChatBubbleOutlineIcon /></ListItemIcon>
+            <ListItemText primary={subscription.shortUrl()}/>
+        </ListItemButton>
+    );
+}
+
+export default Navigation;