Make a ‘View Source’ Button

Avatar of Chris Coyier
Chris Coyier on (Updated on )

Remy Sharp’s cool site for HTML5 demos has a “View Source” button on each of the individual demo pages. Click it, and you see the entire source code for the page you are looking at. It’s not a popup or a new tab, it just shows the source right there on the page. I thought that was cool so I set out to recreate it my own way.

The Fancy Way

View Demo   Download Files

The idea that first came to mind was to use CSS3’s :target pseudo class. We talked about these a while back while exporting CSS3 tabs. The idea is to have a link that links to the #source-code hash tag. That puts #source-code at the end of the URL, and allows the :target selector to match and apply styling. The basics:

<a href="#source-code">View Source</a>
#source-code { display: none; }
#source-code:target { display: block; }

Now it’s just a matter of filling that #source-code element with the actual source code. That is JavaScript territory, since we’ll want to pull that code dynamically, not actually repeat the source code just for sake of display. This way whenever we alter the page, we don’t have to adjust anything, our View Source button shows the updated source code as written. We can lean on jQuery to grab this for us:

var html = $("html").html();

That will give us all the HTML for the page, excluding only the DOCTYPE and actual <html> tags. You could also access this through document.documentElement.innerHTML but hey, if we’re gonna use jQuery let’s just use it. We’ll create a brand new <pre> element, and fill it with a “fake” DOCTYPE and html tags, and then drop in that HTML that we just gathered from the page.

A few quick considerations with that gathered HTML: 1) Let’s escape the <‘s so they show on the page correctly without trying to render as actual HTML. 2) Let’s “linkify” any links it finds so they can be clickable (taken in part from here).

Then we’ll place that newly created <pre> inside our #source-code div.

$(function() {
	$("<pre />", {
		"html":   '&lt;!DOCTYPE html>\n&lt;html>\n' + 
				$("html")
					.html()
					.replace(/[<>]/g, function(m) { return {'<':'&lt;','>':'&gt;'}[m]})
					.replace(/((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi,'<a href="$1">$1</a>') + 
				'\n&lt;/html>'
	}).appendTo("#source-code");
});

Closing the source code is deliciously simple. Since the “View Source” button, when clicked, adds a hash-tag to the page, that means that the “Back” button in the browser will work. Pressing it removes the hash tag, thus #source-code is no longer :targeted, and it is automatically hidden by CSS. The #source-code div also has within it a simple “X” graphic, which links to the hash tag “#”, which has the exact same effect.

This just links to “#”, which takes our source viewing element out of :target, which instantly hides it.

Styling the code

One of the easiest ways to apply syntax highlighting to code is the google-code-prettify project. This is a JavaScript based highlighter. Essentially you link up the JavaScript file and the CSS file that comes with the download:

<link rel='stylesheet' href='css/prettify.css' />
<script src="prettify/prettify.js"></script>

Make sure your <pre> tags have a class of “prettyprint”. I added this to the element creation syntax we’re using to create the <pre>:

"class": "prettyprint"

and call the prettyPrint() function when the page is ready. They recommend adding an onload to the body tag, but since we’re using the jQuery DOM ready function, we can just call it inside there.

I altered the colors a bit to work on the dark background. This is the top part of the prettify.css file:

.str { color: #61ff74; }
.kwd { color: #ea5eff; }
.com { color: white; }
.typ { color: red; }
.lit { color: red; }
.pun { color: white; }
.pln { color: white; }
.tag { color: #ffab58; }
.atn { color: #fabb4e; }
.atv { color: #ffd996; }
.dec { color: red; }

Prettify works by wrapping parts of the code in spans, which colorize that part. Also notice the properly escaped characters.

Compatibility

Pretty much everything modern, as long as it supports CSS3 :target. Breaks in IE 8 and down, but OK in IE 9.

Primitive Method

Firefox and Chrome support the URL protocol “view-source:” which opens up its native source code viewer. If you are making these links only for yourself, you could do:

<a class="button" onClick='window.location="view-source:" + window.location.href'>View Source</a>

Remy’s Method

Turns out the way I did it is pretty much nothing like how it’s done on the HTML5 demos pages. This is my attempt at explaining his technique:

  1. Watch for all clicks
  2. If click was on a link with hash-tag #view-source…
  3. Add a class name of .view-source to the body (this class reveals the otherwise hidden <pre>)
  4. If there isn’t one already, append a <pre> to the body with ID #view-source
  5. <pre> is filled with HTML taken from document.documentElement.innerHTML
  6. Set a timer to check ever 200 milliseconds if the URL still has the hash tag #view-source on it
  7. If the hash tag is gone or has changed, remove the class name from the body (hiding the <pre>) and cancel the timer.
(function () {

var pre = document.createElement('pre');
pre.id = "view-source"

// private scope to avoid conflicts with demos
addEvent(window, 'click', function (event) {
  if (event.target.hash == '#view-source') {
    // event.preventDefault();
    if (!document.getElementById('view-source')) {
      pre.innerHTML = ('<!DOCTYPE html>\n<html>\n' + document.documentElement.innerHTML + '\n</html>').replace(/[<>]/g, function (m) { return {'<':'&lt;','>':'&gt;'}[m]});
      document.body.appendChild(pre);      
    }
    document.body.className = 'view-source';
    
    var sourceTimer = setInterval(function () {
      if (window.location.hash != '#view-source') {
        clearInterval(sourceTimer);
        document.body.className = '';
      }
    }, 200);
  }
});
  
})();

And then the clever bit of CSS which allows the source code to be hidden normally and take over the screen when the body acquires the .view-source class:

#view-source {
  display: none;
}

body.view-source > * {
  display: none;
}

body.view-source #view-source {
  display: block !important;
}

Big time benefits

The cool part about Remy’s method is that it’s far more cross-browser compatible than my idea. It uses pure JavaScript, so it’s not library dependent at all, and it doesn’t use any technique that is “fancy” and wouldn’t work in older(ish) browsers. He could have used the hashchange event, for example, to watch for when the #view-source goes away, but that’s not supported in some older browsers so even that was handled well.

Usage

Of course, feel free to use this however you would like.

View Demo   Download Files

In its current form, this code relies on certain markup on the page, namely the button itself and the #view-source div. This could definitely be converted into a plugin which appends those things automatically which would make this much easier to implement. I may do that eventually.

This also has me thinking that 1) I really need to get on putting in syntax highlighting back into the blog design itself here on CSS-Tricks and 2) I should do this View Source thing on all demo pages. Both of those things will get done in time.

Another thing that would be cool is to bookmarkletize this. That would be especially cool for Safari which has crappy View Source (although there is an extension to fix that). Still, none of the browsers do view source in a modal window, which I think is sometimes nicer than opening a new window or tab.