Skip to content

Bookmarklet for Creating a CSV From an HTML Table

We have a wiki at work that we use for documentation called Confluence. It has the ability to export pages to Word or PDF, but a lacking feature is the ability to take a table and export it for Excel. So, I decided to create a bookmarklet that will allow you to select an HTML table on any web page and create a CSV file from that table that can be downloaded to your machine. Below is the bookmarklet. Just drag it to your bookmarks toolbar. Then give it a shot by clicking the bookmarklet and the below example table should get a link right before it that says “Export to CSV”. Click that link and you will be prompted to download the CSV version of that table. Let me know if it is useful for you.

On thing of note, this will not work correctly in Internet Explorer 9 and below as IE will not allow data uri’s for anything other than images.

Bookmarklet:
Export to CSV <- drag this to your bookmarks toolbar

Update:
05/08/2019 – Enhanced to not kill line breaks.
09/16/2016 – Now works with IE 10+.
04/19/2016 – Fixed issue with tables that have header cells not on top.

Example Table:

Heading 1Heading 2Heading 3Heading 4Heading 5Heading 6
Data 1, 1Data 1, 2Data 1, 3Data 1, 4Data 1, 5Data 1, 6
Data 2, 1Data 2, 2Data 2, 3Data 2, 4Data 2, 5Data 2, 6
Data 3, 1Data 3, 2Data 3, 3Data 3, 4Data 3, 5Data 3, 6
Data 4, 1Data 4, 2Data 4, 3Data 4, 4Data 4, 5Data 4, 6
Data 5, 1Data 5, 2Data 5, 3Data 5, 4Data 5, 5Data 5, 6
Data 6, 1Data 6, 2Data 6, 3Data 6, 4Data 6, 5Data 6, 6

Bookmarklet Source: 

javascript:(function(){
    function getJavaScript(url, success) {
        var script = document.createElement('script');
            script.src = url;
        var head = document.getElementsByTagName('head')[0],
            done = false;
        script.onload = script.onreadystatechange = function(){
            if (!done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) {
                done = true;
                success();
                script.onload = script.onreadystatechange = null;
                head.removeChild(script);
            }
        };
        head.appendChild(script);
    }
    function addCSVLinks() {
        jQuery('.csvLink').remove();
        
        jQuery('table').each(function(index){
            jQuery(this).attr('data-csvtable', index).before('<a href="#" class="csvLink" data-forcsvtable="' + index + '">Export to CSV</a>');
        });
        
        jQuery('.csvLink').click(function(){
            var text = '';
            var csvTableIndex = jQuery(this).attr('data-forcsvtable');
            jQuery('table[data-csvtable="' + csvTableIndex + '"] tr').each(function(){
                jQuery('td, th', this).each(function(index){
                    if(index != 0) {
                        text += ',';
                    }
                    text += '"' + formatedText(jQuery(this).html()) + '"';
                });
                text += '\r\n';
            });
            jQuery('.csvLink').remove();
            downloadCSVFile('TableExport.csv', 'text/csv', text);
        });
    }
	function formatedText(html) {
		var ret = html;
		
		//replace line breaks
		ret = ret.replace(/\n/g, ' ');
		
		//replace tabs
		ret = ret.replace(/\t/g, ' ');
		
		//replace multiple spaces
		ret = ret.replace(/\s+/g, ' ');
		
		//Fix html encoded characters
		ret = decodeHtml(ret);
		
		//Deal with lines breaks and paragraphs
		ret = ret.replace(/<br>/ig, '\n<br>');
		ret = ret.replace(/<br/ig, '\n<br ');
		ret = ret.replace(/<p/ig, '\n<p ');
		
		//Deal with quotes
		ret = ret.replace(/"/ig, '""');
		
		//Deal first character being line break
		ret = ret.replace(/^\n/, '');
		
		//Remove HTML tags
		ret = ret.replace(/(<([^>]+)>)/ig,"");

		return ret;
	}
	function decodeHtml(html) {
		var txt = document.createElement('textarea');
		txt.innerHTML = html;
		return txt.value;
	}
    function downloadCSVFile(filename, mime, text) {
        if (window.navigator.msSaveOrOpenBlob){
            // IE 10+
            var blob = new Blob([decodeURIComponent(encodeURI(text))], {
                type: 'text/csv;charset=utf-8'
            });
            window.navigator.msSaveBlob(blob, filename);
        } else {
            var pom = document.createElement('a');
            pom.setAttribute('href', 'data:' + mime + ';charset=utf-8,' + encodeURIComponent(text));
            pom.setAttribute('download', filename);
            document.body.appendChild(pom);
            pom.click();
            document.body.removeChild(pom);
        }
    }
    if(typeof jQuery == 'undefined') {
        getJavaScript(
            '//code.jquery.com/jquery-latest.min.js',
            function(){
                addCSVLinks();
            }
        )
    } else {
        addCSVLinks();
    }
})();

92 thoughts on “Bookmarklet for Creating a CSV From an HTML Table”

  1. Hello, when I click on the Export to CSV link (after clicking the bookmarklet), the resulting csv file only contains the first column.

    All of my tables have only two columns with the left column acting as a “header” and right column containing data/values.

    I am using Chrome (on Windows), with Confluence 5.8.8.

    Any help would be appreciated. Cheers!

  2. There seems to be a problem with exporting tables that contain merged cells.

    I have a LOT of merged cells in the table I want to export, since it would be very confusing to look at otherwise. But the bookmarklet doesn’t seem to be very friendly with merged cells. I doubt that can be fixed, can it?

    Works just fine for “normal” tables though, so thanks anyways

    1. Hmm … not sure how the best way would be to handle tables with merged cells as those would not translate nicely to csv. I’ll think on it.

  3. Thank you very much. You saved my bacon. I am a non-technical PM and was gnashing my teeth trying to sum up our progress for management until I found your utility.

  4. Hey there,

    great job! Just one thing: could you publish a version with “;” as separator instead of “,”? I found the part in the code but can’t figure out how to change it in the boomarklet 🙁

    Best Regards
    Dmitry

  5. I thrashed for a bit trying to find a solution until I found your bookmarklet. Worked great with Chrome Version 53.0.2785.143 (64-bit) — thank you!

  6. I seem to have encoding issues. My confluence is set to UTF-8 in general settings, and if I understand it correctly, your script is supposed to export UTF-8, but the export clearly has some artifacts, and it does not match what I see on the screen in confluence. Even  s are replaced with  . Is there a way you could help me troubleshoot this?

      1. Similar here; superscripts and math symbols are garbled; still saves a tonne of work but it would be great if there was a function that could be easily enhanced with known search/replace requirements post-export.

        1. The BOM modification referenced further down this comment block fixes the garbled math symbols. Makes no difference for the super/subscript issues; they come through as regular letters on the same baseline as the rest of the content.

  7. Hi. This has been very useful, but for some reason I now cannot “drag and drop” the export to cvs bookmarklet to my favorite bar. I am using IE, but in other browsers I was unable also. This was not a problem previously. Do you have any suggestions for help or where I can find something similar.

  8. This is a great tool, thank you!

    Is there a way for this bookmarklet to include the links that might exist in the tables as well?

  9. Does the input data stay local to the browser ? I’d like to use this, but the data I work with is confidential and cannot be transmitted outside of the corporate network and approved partners. I noticed this hostname in the script, which is why I asked – code.jquery.com

    1. Yes, it stays local. That is simply injecting jQuery into the page to make it easier to work with if jQuery is not already in the page. Nothing is transmitted anywhere.

  10. Thank you so much, very helpful.

    I have many tables on one page, any way to click once and get all tables in different excel worksheets in same excel workbook.

  11. This is great! But I get many blank cells in the output (where data should be). I wonder what could be causing some cells to output as nothing.

  12. Hello Davin! Could you clarify, why it could cause the following error (I’m using Chrome?

    Refused to load the script ‘https://code.jquery.com/jquery-latest.min.js’ because it violates the following Content Security Policy directive: “script-src ‘self’ ‘unsafe-inline’ ‘unsafe-eval’ https://*.google.com https://*.googleapis.com https://*.googlesyndication.com https://*.googleadservices.com https://*.gravatar.com https://*.gstatic.com https://*.wp.com https://wordpress.com https://s.w.org https://www.googletagservices.com https://googleads.g.doubleclick.net https://cdn.ampproject.org https://www.googletagmanager.com https://www.google-analytics.com“. Note that ‘script-src-elem’ was not explicitly set, so ‘script-src’ is used as a fallback.

    1. Hmm. Sounds like the site has a content security policy that is blocking the bookmarklet. A content security policy is a set of instructions that a website sends to your browser that says “For my site only accept javascript/css/images/etc for this site from these locations.” It’s a security mechanism meant to protect users of a site from cross site scripting attacks. What site were you trying it on?

  13. Hey Davin, you’re a doll for this. So incredibly useful and helpful, thank you so much for spending your time to make this and share it freely. I appreciate it very much and you’ve inspired me to follow in your footsteps and contribute in such a way to the developer community. I wish you the best!

  14. Love love love this tool. We have been using it for years. Question: any idea how to make checkboxes [√] download in some form? It would be nice to have a something like a “1”= checked and “0” = not checked. Anything to differentiate checked vs. not checked.

      1. I was hoping to speak with you about this bookmarklet – it is throwing errors in our dev envt so i can’t get it to work – I also sent you a LinkedIn request so that I could ask you about this. Hopefully you get this reply. Many thanks in advance, Steve Whittle

    1. Hi Chris! If you installed this and got it working for yourself, what version of Confluence are you using that the bookmarklet worked with?

  15. Hi,
    I am unable to save the link Export to CSV on Confluence page, is it possible to save it permanently or does it required to every time click the book mark when I want to export ?

    I am not able to share with my team members to use it due to to this.
    any suggestion ?

    Thanks

  16. This tool is great! I do have 1-2 people who aren’t seeing the columns properly in the excel spreadsheet (eg. if it’s 3 columns in Confluence, it’s showing all in 1 column in the Excel spreadsheet). Wondering if this has happened to others or if it’s just an importing settings issue in Excel for this person?

  17. This is really great! Thank you for doing it. I’m noticing in the code that the csv file should be named “TableExport.csv” but I’m getting “download.csv”.

  18. This is really great! Thank you for doing it. I’m noticing in the code that the csv file should be named “TableExport.csv” but I’m getting “download.csv”. Am I doing something wrong?

Leave a Reply

Your email address will not be published. Required fields are marked *