36

I have several pages on a website that use the same header for each page. I was wondering if there was some way to simply reference a file with the html for the header sort of like in this pseudo code:

<!-- Main Page -->

<body>
  <html_import_element src = "myheadertemplate.html">
<body>

Then in a separate file:

<!-- my header template html -->

<div>
  <h1>This is my header</h1>
  <div id = "navbar">
    <div class = "Tab">Home</div>
    <div class = "Tab">Contact</div>
  </div>
</div>

This way I could write the header html once and just import it in each of my pages where I need it by writing one simple tag. Is this possible? Can I do this with XML?

11
  • not with pure html. But you most server side languages supports some type of include capability. What server will you be hosting your site on? (you could also use JS to do it but it would not be search engine friendly) Commented Apr 3, 2016 at 16:02
  • You can do this client side, using a templating library such as Underscore.js - see link here : - underscorejs.org
    – aphextwix
    Commented Apr 3, 2016 at 16:03
  • underscorejs is WAY too big for something like this, a simple ajax request would suffice...In jquery that would look like: $.get("header.htm", function(data) {$("#header").html(data);}); Commented Apr 3, 2016 at 16:07
  • 1
    @FelixKling Technically you're wrong, the frame element was actually made just for that purpose in the past but is now deprecated since server side code is a way better way of doing it. Commented Apr 3, 2016 at 16:15
  • 1
    @seahorsepip: You are right, completely forgot about frames... but yeah, we wouldn't want to suggest deprecated features, so "no" is still both correct and incorrect :P Commented Apr 3, 2016 at 16:19

5 Answers 5

18

You could do it in this fashion below.

<head>
  <link rel="import" href="myheadertemplate.html">
</head>

where you could have your myheadertemplate.html

<div>
  <h1>This is my header</h1>
  <div id = "navbar">
    <div class = "Tab">Home</div>
    <div class = "Tab">Contact</div>
  </div>
</div>

You can then use it with JS below

var content = document.querySelector('link[rel="import"]').import;
7
  • 1
    An ajax request makes more sense since above is html5 only :/ But nice code though, never knew import beyond css import myself ^^ Commented Apr 3, 2016 at 16:18
  • 1
    yeah I came across sometime back while exploring WebComponents and Advanced HTML5
    – Shadab K
    Commented Apr 3, 2016 at 16:30
  • 1
    Actually, this is pretty much what I'm looking for. Cutting edge answer! I found a great explanation of what you're talking about here: link
    – Frank
    Commented Apr 3, 2016 at 17:31
  • Wow, this is an awesome frontend-only solution. I legitimately never saw anyone else post this method in any of the related questions here on SO. Not sure if I'm missing something, but I don't need the JS part for this to work Commented Dec 4, 2019 at 7:00
  • 15
    Please note that this behavior is deprecated and should no longer be used: caniuse.com/#feat=imports Commented Feb 23, 2020 at 1:54
13

So, after a long time I actually found a way to do this using AJAX. HTML Imports are a great solution, but the support across browsers is severely lacking as of 04/2017, so I came up with a better solution. Here's my source code:

function HTMLImporter() {}

HTMLImporter.import = function (url) {
  var error, http_request, load, script;

  script =
    document.currentScript || document.scripts[document.scripts.length - 1];

  load = function (event) {
    var attribute, index, index1, new_script, old_script, scripts, wrapper;

    wrapper = document.createElement("div");
    wrapper.innerHTML = this.responseText;

    scripts = wrapper.getElementsByTagName("SCRIPT");

    for (index = scripts.length - 1; index > -1; --index) {
      old_script = scripts[index];

      new_script = document.createElement("script");
      new_script.innerHTML = old_script.innerHTML;

      for (index1 = old_script.attributes.length - 1; index1 > -1; --index1) {
        attribute = old_script.attributes[index1];
        new_script.setAttribute(attribute.name, attribute.value);
      }

      old_script.parentNode.replaceChild(new_script, old_script);
    }

    while (wrapper.firstChild) {
      script.parentNode.insertBefore(
        wrapper.removeChild(wrapper.firstChild),
        script
      );
    }

    script.parentNode.removeChild(script);

    this.removeEventListener("error", error);
    this.removeEventListener("load", load);
  };

  error = function (event) {
    this.removeEventListener("error", error);
    this.removeEventListener("load", load);

    alert("there was an error!");
  };

  http_request = new XMLHttpRequest();
  http_request.addEventListener("error", error);
  http_request.addEventListener("load", load);
  http_request.open("GET", url);
  http_request.send();
};

Now when I want to import HTML into another document, all I have to do is add a script tag like this:

<script>HTMLImporter.import("my-template.html");</script>

My function will actually replace the script tag used to call the import with the contents of my-template.html and it will execute any scripts found in the template. No special format is required for the template, just write the HTML you want to appear in your code.

3
  • But you need to add the script to every single file you want to reuse the <head> though, right? I think the only way to really manage what you want to do is to implement a site with dynamic web pages where the server generates pages on the fly with the right template.
    – guero64
    Commented Jan 4, 2023 at 12:52
  • @guero64 You put the script into a separate file and use a script tag with src="sepFile.js". Then you only need to add two script tags to each html file. I'm not going to test this, because I would rather use a back end solution, but I'm pretty sure it would work. Commented Feb 24, 2023 at 4:46
  • For me this doesn't work, because I get this error: developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/… because my template.html file is local. Commented Aug 14 at 17:04
1

I had found this solution. On each page I added the script :

<script type="module" src="main.js"></script>

and the tag

<common-header></common-header>.

and everything works perfectly.

I don't know if it's very performant and efficient.

    ....some code...
        <script type="module" src="main.js"></script>
    </head>
    <body>
    <common-header></common-header>

main.js:

class CommonHeader extends HTMLElement {
  
connectedCallback(){
    this.innerHTML = `
    <div class="header">
        <div class="logo">
            <img class="img" src="assets/Logo2.png" alt="logo" />
        </div>
        <ul class="menu">
        <li><a href="./index.html" class="">Home</a></li>
        <li><a href="./single.html" class="">Single</a></li>
        <li><a href="./contact.html" class="">Contact</a></li>
        </ul>
        <div class="cta">
            <a href="" class="button">Chiamami </a>
        </div>
        <div class="hamburger"><span></span><span></span><span></span> 
        </div>
  </div> `
    }
}
customElements.define('common-header', CommonHeader)
1
0

As far as I know it's not possible. You can load the header as a webpage in a iframe element though. In the past webpages were built with frame elements to load seperate parts of a webpage, this is not recommended and support in current browsers is due to legacy.

In most cases this is done with server side languages like php with as example include("header.php");.

4
  • But all the code would be html only, so there's no dynamic content. I'm using NodeJS, so I guess it wouldn't be that hard to do, but it seems like some pretty simple functionality, so I was hoping it might already exist.
    – Frank
    Commented Apr 3, 2016 at 16:06
  • I believe you can also use <object> tag to insert html removing the need to use an iframe.
    – GillesC
    Commented Apr 3, 2016 at 16:06
  • The object tag works mostly the same as an iframe tag in this case and is only supported in modern browsers. Commented Apr 3, 2016 at 16:10
  • 1
    I would make no sense in html itself since html is a plain text xml language that should NOT be dynamic so something like <get data="header.html"> should not be replaced with the html content of header.html. @Frank Commented Apr 3, 2016 at 16:12
0

I'm pretty new to HTML and this question is quite old, but I think I have a solution? Import a javascript file into each page that redefines the innerHTML of elements you want to reuse, then all you have to do is update the javascript.

So for example, each HTML page looks like this:

<head>
  <script src="templates.js" defer></script>
  <div id="reused-header"></div>
  <!--other header elements-->
</head>

<body>
  <div id="reused-element"></div>
  <!--rest of the page-->
</body>

And you can include the HTML to update in a JavaScript file as innerHTML text like this, and updating the JS text updates the reused elements on every other page:

document.getElementById("reused-header").innerHTML = `
<!--html to reuse here-->`;

document.getElementById("reused-element").innerHTML = `
<!--html to reuse here-->`;

Not the answer you're looking for? Browse other questions tagged or ask your own question.