diff --git a/src/main/java/htmlpublisher/HtmlPublisher.java b/src/main/java/htmlpublisher/HtmlPublisher.java
index 396f7bb..3be0801 100644
--- a/src/main/java/htmlpublisher/HtmlPublisher.java
+++ b/src/main/java/htmlpublisher/HtmlPublisher.java
@@ -48,6 +48,7 @@
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import hudson.util.DirScanner;
 import jenkins.util.SystemProperties;
+import org.apache.commons.lang.StringUtils;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.accmod.restrictions.suppressions.SuppressRestrictedWarnings;
@@ -60,6 +61,7 @@
 import hudson.FilePath;
 import hudson.Launcher;
 import hudson.Util;
+import hudson.Functions;
 import hudson.matrix.MatrixConfiguration;
 import hudson.matrix.MatrixProject;
 import hudson.model.AbstractBuild;
@@ -237,6 +239,7 @@ public static boolean publishReports(Run<?, ?> build, FilePath workspace, TaskLi
         for (int i=0; i < reportTargets.size(); i++) {
             // Create an array of lines we will eventually write out, initially the header.
             List<String> reportLines = new ArrayList<>(headerLines);
+            reportLines.add("<script type=\"text/javascript\" src=\"" + getStaticResourcesUrl() + "/plugin/htmlpublisher/js/htmlpublisher.js\"></script>");
             HtmlPublisherTarget reportTarget = reportTargets.get(i);
             boolean keepAll = reportTarget.getKeepAll();
             boolean allowMissing = reportTarget.getAllowMissing();
@@ -338,23 +341,14 @@ public static boolean publishReports(Run<?, ?> build, FilePath workspace, TaskLi
                 } else {
                     reportFile = report;
                 }
-                String tabItem = "<li id=\"" + tabNo + "\" class=\"unselected\" onclick=\"updateBody('" + tabNo + "');\" value=\"" + htmlAttributeEscape(report) + "\">" + htmlAttributeEscape(getTitle(reportFile, titles, j)) + "</li>";
+                String tabItem = "<li id=\"" + tabNo + "\" class=\"unselected\" value=\"" + htmlAttributeEscape(report) + "\">" + htmlAttributeEscape(getTitle(reportFile, titles, j)) + "</li>";
                 reportLines.add(tabItem);
             }
             // Add the JS to change the link as appropriate.
             String hudsonUrl = Jenkins.get().getRootUrl();
             Job job = build.getParent();
-            reportLines.add("<script type=\"text/javascript\">document.getElementById(\"hudson_link\").innerHTML=\"Back to " + htmlAttributeEscape(job.getName()) + "\";</script>");
-            // If the URL isn't configured in Hudson, the best we can do is attempt to go Back.
-            if (hudsonUrl == null) {
-                reportLines.add("<script type=\"text/javascript\">document.getElementById(\"hudson_link\").onclick = function() { history.go(-1); return false; };</script>");
-            } else {
-                String jobUrl = hudsonUrl + job.getUrl();
-                reportLines.add("<script type=\"text/javascript\">document.getElementById(\"hudson_link\").href=\"" + jobUrl + "\";</script>");
-            }
-
-            reportLines.add("<script type=\"text/javascript\">document.getElementById(\"zip_link\").href=\"*zip*/" + reportTarget.getSanitizedName() + ".zip\";</script>");
-
+            reportLines.add("<span class='links-data-holder' data-back-to-name='" + job.getName() + "' data-root-url='" +
+                    hudsonUrl + "' data-job-url='" + job.getUrl() + "' data-zip-link='" + reportTarget.getSanitizedName() + "'/>");
             // Now add the footer.
             reportLines.addAll(footerLines);
             // And write this as the index
@@ -398,6 +392,15 @@ public Collection<? extends Action> getProjectActions(AbstractProject<?, ?> proj
         }
     }
 
+    private static String getStaticResourcesUrl() {
+        String rootUrl = Jenkins.get().getRootUrl();
+        if (rootUrl == null) {
+            rootUrl = "";
+        }
+
+        return StringUtils.stripEnd(rootUrl, "/") + Functions.getResourcePath();
+    }
+
     private static void adjustMatrixProject(AbstractProject<?, ?> project) {
         MatrixProject mp = (MatrixProject) project;
         if (mp.getActiveConfigurations() != null) {
diff --git a/src/main/resources/htmlpublisher/HtmlPublisher/header.html b/src/main/resources/htmlpublisher/HtmlPublisher/header.html
index 01e2d92..71bf735 100644
--- a/src/main/resources/htmlpublisher/HtmlPublisher/header.html
+++ b/src/main/resources/htmlpublisher/HtmlPublisher/header.html
@@ -86,26 +86,9 @@
 }
 
 </style>
-
-<script type="text/javascript">
-function updateBody(tabId, page) {
-    document.getElementById(selectedTab).setAttribute("class", "unselected");
-    tab = document.getElementById(tabId)
-    tab.setAttribute("class", "selected");
-    selectedTab = tabId;
-    iframe = document.getElementById("myframe");
-    iframe.src = encodeURIComponent(tab.getAttribute("value")).replace(/%2F/g, '/');
-}
-function init(tabId){
-	updateBody(tabId);
-}
-
-var selectedTab = "tab1"
-</script>
-
 </head>
 
-<body onload="init('tab1');">
+<body>
 <nav>
 <h1><a id="hudson_link" href="#"></a></h1>
 <h2><a id="zip_link" href="#">Zip</a></h2>
diff --git a/src/main/resources/htmlpublisher/HtmlPublisherTarget/BaseHTMLAction/index.groovy b/src/main/resources/htmlpublisher/HtmlPublisherTarget/BaseHTMLAction/index.groovy
index ab0b282..f9607d2 100644
--- a/src/main/resources/htmlpublisher/HtmlPublisherTarget/BaseHTMLAction/index.groovy
+++ b/src/main/resources/htmlpublisher/HtmlPublisherTarget/BaseHTMLAction/index.groovy
@@ -2,6 +2,7 @@ package htmlpublisher.HtmlPublisherTarget.BaseHTMLAction
 
 import htmlpublisher.HtmlPublisher
 import htmlpublisher.HtmlPublisherTarget
+import hudson.Functions
 import hudson.Util
 import hudson.model.Descriptor
 
@@ -10,6 +11,8 @@ import java.security.MessageDigest
 l = namespace(lib.LayoutTagLib)
 st = namespace("jelly:stapler")
 
+Functions.initPageVariables(context)
+
 def text = new File(my.dir(), my.getHTMLTarget().getWrapperName()).text
 
 def actual = Util.toHexString(MessageDigest.getInstance("SHA-1").digest(text.getBytes("UTF-8")))
@@ -26,9 +29,10 @@ def serveWrapper() {
     def footer = HtmlPublisher.class.getResourceAsStream("/htmlpublisher/HtmlPublisher/footer.html").text
 
     raw(header)
+    script(src: "${resURL}/plugin/htmlpublisher/js/htmlpublisher.js", type: "text/javascript")
 
     def legacyFile = new File(my.dir(), "htmlpublisher-wrapper.html")
-    def matcher = legacyFile.text =~ /<li id="tab\d+" class="unselected" onclick="updateBody\('tab\d+'\);" value="([^"]+)">([^<]+)<\/li>/
+    def matcher = legacyFile.text =~ /<li id="tab\d+" class="unselected"(?: onclick="updateBody\('tab\d+'\);")? value="([^"]+)">([^<]+)<\/li>/
 
     def items = []
     def itemsTitle = []
@@ -39,14 +43,15 @@ def serveWrapper() {
 
     def idx = 1
     items.each { file ->
-        li(itemsTitle[idx - 1], id: "tab${idx}", class: "unselected", onclick: "updateBody('tab${idx}')", value: file.trim())
+        li(itemsTitle[idx - 1], id: "tab${idx}", class: "unselected", value: file.trim())
         idx++
     }
 
-    // TODO replace unnecessary JS usage by properly integrating header.html/footer.html in this groovy view
-    raw("<script type=\"text/javascript\">document.getElementById(\"hudson_link\").innerHTML=\"Back to ${my.backToName}\";</script>")
-    raw("<script type=\"text/javascript\">document.getElementById(\"hudson_link\").href=\"${rootURL}/${my.backToUrl}\";</script>")
-    raw("<script type=\"text/javascript\">document.getElementById(\"zip_link\").href=\"*zip*/${my.getHTMLTarget().sanitizedName}.zip\";</script>")
+    span(class: "links-data-holder", 
+            "data-back-to-name": "${my.backToName}",
+            "data-root-url": "${rootURL}",
+            "data-job-url": "${my.backToUrl}",
+            "data-zip-link": "${my.getHTMLTarget().sanitizedName}")
 
     raw(footer)
 }
diff --git a/src/main/webapp/js/htmlpublisher.js b/src/main/webapp/js/htmlpublisher.js
new file mode 100644
index 0000000..f52ed2a
--- /dev/null
+++ b/src/main/webapp/js/htmlpublisher.js
@@ -0,0 +1,31 @@
+function updateBody(tabId) {
+  document.getElementById(selectedTab).setAttribute("class", "unselected");
+  tab = document.getElementById(tabId)
+  tab.setAttribute("class", "selected");
+  selectedTab = tabId;
+  iframe = document.getElementById("myframe");
+  iframe.src = encodeURIComponent(tab.getAttribute("value")).replace(/%2F/g, '/');
+}
+function init(tabId){
+  updateBody(tabId);
+}
+
+var selectedTab = "tab1";
+
+window.addEventListener("DOMContentLoaded", () => {
+  init("tab1");
+  
+  const dataHolder = document.querySelector(".links-data-holder");
+  const { backToName, rootUrl, jobUrl, zipLink } = dataHolder.dataset;
+  const backButton = document.querySelector("#hudson_link");
+  backButton.innerText = `Back to ${backToName}`;
+  backButton.href = `${rootUrl}/${jobUrl}`;
+
+  document.querySelector("#zip_link").href = `*zip*/${zipLink}.zip`;
+  
+  document.querySelectorAll("#tabnav li").forEach((item) => {
+    item.addEventListener("click", (event) => {
+      updateBody(event.target.id);
+    });
+  });
+});