diff --git a/scripts/build.js b/scripts/build.js
index 5bd584a46e0a2b16f8ef12da08d06187e7986d62..1fdb7a233d1a881e349dc391bdb15320ecb3bf03 100644
--- a/scripts/build.js
+++ b/scripts/build.js
@@ -146,7 +146,7 @@ function buildAppleAssociatedAppsFile(clients) {
 async function buildCss(entryPath, targetDir, assets) {
     entryPath = path.join(projectDir, entryPath);
     const assetUrlMapper = ({absolutePath}) => {
-        const relPath = absolutePath.substr(projectDir.length);
+        const relPath = absolutePath.slice(projectDir.length);
         return assets.resolve(path.join(targetDir, relPath));
     };
 
@@ -211,7 +211,7 @@ class AssetMap {
             if (!resourcePath.startsWith(this._targetDir)) {
                 throw new Error(`absolute path ${resourcePath} that is not within target dir ${this._targetDir}`);
             }
-            relPath = resourcePath.substr(this._targetDir.length + 1); // + 1 for the /
+            relPath = resourcePath.slice(this._targetDir.length + 1); // + 1 for the /
         }
         return relPath;
     }
@@ -267,7 +267,7 @@ class AssetMap {
         if (!assetMap.directory.startsWith(this.directory)) {
             throw new Error(`map directory doesn't start with this directory: ${assetMap.directory} ${this.directory}`);
         }
-        const relSubRoot = assetMap.directory.substr(this.directory.length + 1);
+        const relSubRoot = assetMap.directory.slice(this.directory.length + 1);
         for (const [key, value] of assetMap._assets.entries()) {
             this._assets.set(path.join(relSubRoot, key), path.join(relSubRoot, value));
         }
diff --git a/src/Link.js b/src/Link.js
index 47270778220049239f251352af8c980e514d785b..33e496fcba9221effcc8fc72e44f997b13406d54 100644
--- a/src/Link.js
+++ b/src/Link.js
@@ -45,8 +45,8 @@ function getWebInstanceMap(queryParams) {
     const postfix = "]";
     const webInstanceParams = queryParams.filter(([key]) => key.startsWith(prefix) && key.endsWith(postfix));
     const webInstances = webInstanceParams.map(([key, value]) => {
-        const noPrefix = key.substr(prefix.length);
-        const clientId = noPrefix.substr(0, noPrefix.length - postfix.length);
+        const noPrefix = key.slice(prefix.length);
+        const clientId = noPrefix.slice(0, -postfix.length);
         return [clientId, value];
     });
     return webInstances.reduce((map, [clientId, host]) => {
@@ -110,7 +110,7 @@ export class Link {
         if (!linkStr.startsWith("#/")) {
             return null;
         }
-        linkStr = linkStr.substr(2);
+        linkStr = linkStr.slice(2);
         const [identifier, eventId] = linkStr.split("/");
 
         let viaServers = [];
diff --git a/src/RootViewModel.js b/src/RootViewModel.js
index 05a8cd84a76c8d124ae744c9a4c4ba525c47758e..32257ce9c35b27b5330ec903e16cf9fbf83ca69d 100644
--- a/src/RootViewModel.js
+++ b/src/RootViewModel.js
@@ -66,7 +66,7 @@ export class RootViewModel extends ViewModel {
         this.createLinkViewModel = null;
         let newLink;
         if (hash.startsWith("#/policy/")) {
-            const server = hash.substr(9);
+            const server = hash.slice(9);
             this._updateChildVMs(null, oldLink);
             this.loadServerPolicyViewModel = new LoadServerPolicyViewModel(this.childOptions({server}));
             this.loadServerPolicyViewModel.load();
diff --git a/src/open/ClientViewModel.js b/src/open/ClientViewModel.js
index 398731532f0916085f8d4c41664cd483292e8b6a..2cd724498c3310bb0b8970a025d1a007b53ec3bd 100644
--- a/src/open/ClientViewModel.js
+++ b/src/open/ClientViewModel.js
@@ -139,7 +139,7 @@ export class ClientViewModel extends ViewModel {
             let label = preferredWebInstance;
             const subDomainIdx = preferredWebInstance.lastIndexOf(".", preferredWebInstance.lastIndexOf("."));
             if (subDomainIdx !== -1) {
-                label = preferredWebInstance.substr(preferredWebInstance.length - subDomainIdx + 1);
+                label = preferredWebInstance.slice(preferredWebInstance.length - subDomainIdx + 1);
             }
             return `Hosted by ${label}`;
         }
diff --git a/src/preview/HomeServer.js b/src/preview/HomeServer.js
index 964e1e7782cd272de65f2e98cd36445dc86eda51..a9a9a67a24a27059c8d7cccb1d97f0bb6e7ac198 100644
--- a/src/preview/HomeServer.js
+++ b/src/preview/HomeServer.js
@@ -15,7 +15,7 @@ limitations under the License.
 */
 
 function noTrailingSlash(url) {
-    return url.endsWith("/") ? url.substr(0, url.length - 1) : url;
+    return url.endsWith("/") ? url.slice(0, -1) : url;
 }
 
 export async function resolveServer(request, baseURL) {
@@ -123,7 +123,7 @@ export class HomeServer {
 function parseMxcUrl(url) {
     const prefix = "mxc://";
     if (url.startsWith(prefix)) {
-        return url.substr(prefix.length).split("/", 2);
+        return url.slice(prefix.length).split("/", 2);
     } else {
         return null;
     }
diff --git a/src/utils/TemplateView.js b/src/utils/TemplateView.js
index 349907c4bbdabb728729e3ac501eaf8c7c4024e2..547dd25256b5643097cfb65c1bedba75d98926d4 100644
--- a/src/utils/TemplateView.js
+++ b/src/utils/TemplateView.js
@@ -210,7 +210,7 @@ class TemplateBuilder {
                     setAttribute(node, key, classNames(value));
                 }
             } else if (key.startsWith("on") && key.length > 2 && isFn) {
-                const eventName = key.substr(2, 1).toLowerCase() + key.substr(3);
+                const eventName = key.slice(2, 3).toLowerCase() + key.slice(3);
                 const handler = value;
                 this._templateView._addEventListener(node, eventName, handler);
             } else if (isFn) {