Grow your CSS skills. Land your dream job.

Make a ‘View Source’ Button

Published by Chris Coyier

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.

Comments

  1. This is actually an awesome solution. A lot of times I find that source code written on tutorials or within posts can look a little messy or broken. This is such a fine alternative, thanks dude.

  2. Bradley
    Permalink to comment#

    In FF, when you scroll down the modal, the text becomes all blurry. Just my initial guess but I believe it’s because of the transparency.

  3. Awesome stuff! I will definitely be using this at Perishable Press. Thanks for sharing with us!

    Also, check the download link – I was getting a 404..

  4. wooow very nice work chris thanks a lot

  5. Martin Ansty
    Permalink to comment#

    This is great, more really useful stuff. Especially the fact you have presented a number of methods to accomplish a similar goal. You’re “fancy” method seems to struggle when Modenizr is also in use though; Modenizr appears to add a fair chunk of ugly looking code (mostly an @fontface data string) to the head of the page at some point. By using jQuery to append the html on DOM ready it picks this up. Not a big issue, but I thought I’d mention it in case anyone else was wondering where the big ugly chunk of code was coming from.

  6. Permalink to comment#

    Nice work Chris. Like this a lot.

  7. Permalink to comment#

    This is incredibly useful Chris. Thanks!

  8. Sahan
    Permalink to comment#

    Great idea! Very useful for a psd to html portfolio :)

  9. Permalink to comment#

    Very cool deconstruction – both very valid methods. Just goes to show there’s often more than one right way to do something..

  10. Its really a cool idea, keeping in mind that safari does not show color code. But just so u know this demo is not working in IE8 and Beta IE9

  11. tully
    Permalink to comment#

    Fluff. Why re-invent the wheel? Every browser already has the ability to view source, so aside from unwanted code bloat and the, ‘ooh look, shiny!’ effect, what’s the point? If you’re using this as a demo of the pseudo :target selector then that’s fine, but I wouldn’t advocate that anyone actually use this.

  12. Permalink to comment#

    Wow! very nice work Chris thanks a lot :-)

  13. Forgot to share this from before. Here’s the bookmarklet I wrote to view source. “Why?” might you ask (as Tully above did) – because my iPhone doesn’t have a view source button – nor do most non-desktop browsers:

    javascript:(function(d,h)%7Bh=d.documentElement.innerHTML;d.open();d.write('%3Cpre%3E'+('%3C!DOCTYPE%20html%3E%3Chtml%3E'+h+'%3C/html%3E').replace(/%5B%3C%3E%5D/g,function(m)%7Breturn%7B'%3C':'<','%3E':'>'%7D%5Bm%5D%7D)+'%3C/pre%3E')%7D)(document);

    View Source

    Hope that’s of some use to someone else.

    • tully
      Permalink to comment#

      I would argue that there’s *very* little need to be able to view source from an iPhone or other “non-desktop” browser. Are you doing development on your iPhone? If so, maybe we should start a fund to get you a better working environment ;)

      In reality this functionality should be part of the browser and finding a solution to the problem of a browser lacking basic functionality shouldn’t be left up to web developers, but rather the browser developers.

    • > finding a solution to the problem of a browser lacking basic functionality shouldn’t be left up to web developers

      Riiighht. Like the PNG fix for IE. Or Web Sockets flash shim. Or any of those other techniques where web developers have created solutions for a browsers lacking functionality.

      (sorry, breaking rule #1)

  14. sojabob
    Permalink to comment#

    This is a real useful and nice tool, thanks for showing uns ‘how to’ :)

  15. Really great tutorial, thanks for sharing!

  16. Permalink to comment#

    This is a great way to show your source code. Nice article Chris!

  17. This is really really cool! Thanks for sharing

  18. Very nice! Thanks for sharing!

    This will be perfect for those wanting to check out my code without using the view page source in the browser. I plan to incorporate this into my portfolio of my website in my next round of updates.

  19. All right then. I’m stealing this asap for my demo pages. Good write Chris.

  20. Excellent idea by Remy, and a lot nicer to view source with a bit of styling, excellent tutorial and would be nice additional features to the CSS-Tricks blog to have syntax highlighting and View Source on all demo pages. LT

  21. Permalink to comment#

    the scripts are understandable

    excepts the

    .replace(/((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi,’$1‘) +

    still got no idea

    • Ben Allen
      Permalink to comment#

      Time for you to look into regular expressions me-thinks. This one converts and urls in the source in to clickable links. Damned powerful things when used correctly!

  22. Vertex
    Permalink to comment#

    Is there possibility, to add an external link to show the source ?

  23. amidude
    Permalink to comment#

    Very nice

  24. Is there a way to wrap long lines to prevent horizontal scrolling? Perhaps with a line-continuation character at the beginning of the wrapped lines…

  25. Really nice one. keep it up. Great source of inspiration.

  26. Permalink to comment#

    Old trick but with new features COOL.

  27. Permalink to comment#

    thats really great trick. I ll try & use. thanx..

  28. Hello,

    Your code is good and also allow some tuning…
    But the simple way is to put directly in an href link

    “view-source:http://example.com/mypage.html” et hop ;)

    http://en.wikipedia.org/wiki/View-source_URI_scheme

  29. Permalink to comment#

    Dear Chris,

    WHAT FONT DID YOU USE IN THE PICS!?! Ive been looking all over for it, but icant find the font!

  30. Good tutorial,thanks for sharing i will try this code at my website too. Hope will work.

  31. good solution. Thanks for sharing with us

  32. Permalink to comment#

    thanks for the cool script. I can use it in many place.

  33. Permalink to comment#

    Although knowledge never hurts and it was fun to learn something new, I’m still old school. Also, I didn’t receive a 404 during the download. :)

  34. Permalink to comment#

    Really nice trick, I could deff use this on one of my blogs! Thanks Chris

  35. i’m using Mozilla Firefox 3.6.3 and just write like it, we can make a simple link source:
    View the source
    Hihihi :D
    here are many great tutorials \m/

  36. Really very great Information… and very great solution, thanks for sharing!!!

  37. I like the fancy view source button, but I have a non-antagonistic criticism:
    I don’t like that if I view source, then close the popup, then hit the back button (in attempt to actually go to the previous page), the popup pops back up. I understand it’s because of the hashtag and :target pseudo-element; just saying this one annoyance prevents my enjoyment of it. If there’s a way around it, I’d be interested.

  38. Mohammad Wali
    Permalink to comment#

    Can anyone please explain me how to make a view source button like a syntax highlter use for <pre> tags ?

  39. Similarly, a new version of an operating system might capitalize on neww technologies while forgoing support
    for olld technology or system specifications from years earlier.
    Then how to rip DVD wirh Mac – X DVD Ripper Free Edition.
    See the section below on more information on why some discs fail.

Leave a Comment

Current day month ye@r *

*May or may not contain any actual "CSS" or "Tricks".