Wanted to create a quick and simple generator which made tables suitable for accessibility.
A Pen by nicholasnadel on CodePen.
Wanted to create a quick and simple generator which made tables suitable for accessibility.
A Pen by nicholasnadel on CodePen.
| <div class="codecopiedalert"> | |
| <i class="material-icons">sentiment_very_satisfied</i> | |
| Table Code Copied! | |
| </div> | |
| <h1>Accessible Table Generator</h1> | |
| <div id="maincont" class="container"> | |
| <div id="infodisplay" class="per50 floatleft"> | |
| <h3>Instructions</h3> | |
| <ul> | |
| <li>Select Size</li> | |
| <li>Add caption</li> | |
| <li>Choose column and/or row headers</li> | |
| <li>Click cells to edit them (Ctrl+B for bold etc works) then Click 'Prepare Table Code'</li> | |
| <li>If you're happy, click 'Copy to Clipboard' then Ctrl+V to paste in a location of your choice!</li> | |
| </ul> | |
| </div> | |
| <div class="per50 floatleft coderdy"> | |
| <div id="tablepreview" class=""> | |
| <div class="topbar"><span class="option"> <a id="sizertoggle" href="#" class="material-icons">border_all <span class="label">Size</span> </a> | |
| </span> | |
| <span class="option"> | |
| <a id="captiontoggle" href="#" class="material-icons">speaker_notes <span class="label">Caption</span></a> | |
| </span> | |
| <span class="option"> | |
| <a id="titletoggle" href="#" class="material-icons"><i class="material-icons">view_week</i><span class="label">col & row THs</span> | |
| </a> | |
| </span> | |
| <form><span id="colcount"></span>x<span id="rowcount"></span></form> | |
| <div class="clear"></div> | |
| </div> | |
| <div id="sizer" class="table_size_chooser "><div class="SizeChooser"><table><tbody><tr><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td> </td></tr><tr><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td> </td></tr><tr><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td> </td></tr><tr><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td> </td></tr><tr><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td> </td></tr><tr><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td> </td></tr><tr><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td> </td></tr><tr><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td> </td></tr><tr><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td> </td></tr><tr><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td> </td></tr><tr><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td> </td></tr><tr><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td> </td></tr><tr><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td> </td></tr><tr><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td> </td></tr><tr><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td class=""> </td><td> </td><td> </td></tr></tbody></table> | |
| </div> | |
| </div> <!-- end of sizer --> <div id="captioner"> | |
| <textarea placeholder="Enter caption here"></textarea> | |
| <button id="applycaption">Update Table</button> | |
| </div> | |
| <div id="headerer"> | |
| <input type="checkbox" id="colheadercheck" name="columnheaders" value="columnheaders" checked> Column Headers | |
| <input type="checkbox" | |
| id="rowheadercheck" name="rowheaders" value="rowheaders">Row Headers | |
| <button id="applyheaders">Update Table</button> | |
| </div> | |
| </div> <!-- end of table preview --> | |
| <pre id="tablecode"></pre> | |
| <button class="btn copybtn" data-clipboard-target="#tablecode"> <i class="material-icons">content_copy</i>Copy to Clipboard | |
| </button> | |
| </div> | |
| <div class="clear"></div> | |
| </div> | |
| <div id="tabledisplay" class="per100"> | |
| <h2>Table Preview<button id="gencode"><i class="material-icons">code</i><span id="preparetext">Push edits to code</span></button></h2> | |
| <div class="container"> | |
| <div class="table-responsive"> | |
| </div> | |
| </div> | |
| </div> |
| // highlighter for sizer visuals | |
| $('td').mouseover(function(){ | |
| var $this = $(this); | |
| var col = $this.index(); | |
| var row = $this.closest('tr').index(); | |
| $('#colcount').text(col+1); | |
| $('#rowcount').text(row+1); | |
| }); | |
| $("table").delegate('td','mouseover mouseleave', function(e) { | |
| var cellindex = 0; | |
| if (e.type == 'mouseover') { | |
| $(this).addClass("cell"); | |
| var cells = $(this).parent().children("td"); | |
| for(var i=0;i<cells.length;i++){ | |
| if($(cells[i]).hasClass("cell")){ | |
| $(this).removeClass("cell"); | |
| cellindex = i; | |
| break; | |
| } | |
| } | |
| $(this).parent().addClass("row"); | |
| var rows = $(this).parent().parent().children("tr"); | |
| for(var i=0;i<rows.length;i++){ | |
| var tds = $(rows[i]).children("td"); | |
| for(var j=0;j<=cellindex;j++){ | |
| $(tds[j]).addClass("SizeChooser-hover"); | |
| } | |
| if($(rows[i]).hasClass("row")){ | |
| $(this).parent().removeClass("row"); | |
| break; | |
| } | |
| } | |
| } | |
| else { | |
| $("td").removeClass("SizeChooser-hover"); | |
| } | |
| }); | |
| // END highlighter for sizer visuals | |
| // toggle sizer input | |
| $( "#sizertoggle" ).click(function() { | |
| $("#tablepreview").removeClass("showcaptioner").removeClass("showheaderer"); | |
| $("#tablepreview").toggleClass('showsizer'); | |
| }); | |
| // toggle caption input | |
| $("#captiontoggle").click(function() { | |
| $("#tablepreview").removeClass("showsizer").removeClass("showheaderer"); | |
| $("#tablepreview").toggleClass('showcaptioner'); | |
| }); | |
| $("#titletoggle").click(function() { | |
| $("#tablepreview").removeClass("showsizer").removeClass("showcaptioner"); | |
| $("#tablepreview").toggleClass('showheaderer'); | |
| }); | |
| // on sizer td click, generate new table | |
| $( "#tablepreview td" ).click(function() { | |
| $("#tablepreview").removeClass('showsizer'); | |
| $('#tabledisplay .table-responsive').empty(); | |
| row = $('#colcount').text(); | |
| col = $('#rowcount').text(); | |
| var rows = col; //here's your number of rows and columns | |
| var cols = row; | |
| var table = $('<table class="table table-bordered"><tbody>'); | |
| for(var r = 0; r < rows; r++) | |
| { | |
| var tr = $('<tr>'); | |
| for (var c = 0; c < cols; c++) | |
| $('<td contenteditable="true">click to edit</td>').appendTo(tr); | |
| tr.appendTo(table); | |
| } | |
| table.appendTo('#tabledisplay .table-responsive'); | |
| gencode(); | |
| }); | |
| // BEAUTIFY STRING | |
| function process(str) { | |
| var div = document.createElement('div'); | |
| div.innerHTML = str.trim(); | |
| return format(div, 0).innerHTML; | |
| } | |
| function format(node, level) { | |
| var indentBefore = new Array(level++ + 1).join(' '), | |
| indentAfter = new Array(level - 1).join(' '), | |
| textNode; | |
| for (var i = 0; i < node.children.length; i++) { | |
| textNode = document.createTextNode('\n' + indentBefore); | |
| node.insertBefore(textNode, node.children[i]); | |
| format(node.children[i], level); | |
| if (node.lastElementChild == node.children[i]) { | |
| textNode = document.createTextNode('\n' + indentAfter); | |
| node.appendChild(textNode); | |
| } | |
| } | |
| return node; | |
| } | |
| // ON APPLYING CAPTION | |
| $('button#applycaption').click(function(){ | |
| //remove caption input window | |
| $("#tablepreview").removeClass('showcaptioner'); | |
| var caption = $('#captioner textarea').val(); | |
| $( "#tabledisplay table caption" ).remove(); | |
| gencode(); | |
| }); | |
| // ON APPLYING CAPTION | |
| $('button#applyheaders').click(function(){ | |
| //remove caption input window | |
| $("#tablepreview").removeClass('showheaderer'); | |
| gencode(); | |
| }); | |
| $('#gencode').click(function(){ | |
| gencode(); | |
| $('#preparetext').text('Code Updated Above'); | |
| $("body").addClass("codeupdated").delay(1500).queue(function(){ | |
| $(this).removeClass("codeupdated").dequeue(); | |
| $('#preparetext').text('Push edits to code'); | |
| }); | |
| }); | |
| function gencode(){ | |
| if ($('#rowheadercheck').is(':checked')) { | |
| // add th to first row | |
| $('#tabledisplay tr td:first-child').replaceWith(function(i, html) { | |
| return '<th scope="row">click to edit</th>'; | |
| }); | |
| } | |
| if ( !$('#rowheadercheck').is(':checked')) { | |
| // alert('notcheck'); | |
| // add th to first row | |
| $('#tabledisplay tr th:first-child').replaceWith(function(i, html) { | |
| return '<td contenteditable="true">click to edit</td>'; | |
| }); | |
| } | |
| if ($('#colheadercheck').is(':checked')) { | |
| // add th to first row | |
| $('#tabledisplay tr:first-child').children('td').replaceWith(function(i, html) { | |
| return '<th scope="col">click to edit</th>'; | |
| }); | |
| } | |
| var caption = $('#captioner textarea').val(); | |
| $( "#tabledisplay table caption" ).remove(); | |
| $( "#tabledisplay table" ).prepend( "<caption class='heading'>"+caption+"</caption>" ); | |
| $("th, td").removeAttr("contenteditable"); | |
| // update code display | |
| var htmlString = $( '#tabledisplay .container' ).html(); | |
| $('#tablecode').text(process(htmlString)); | |
| $("#tabledisplay th, #tabledisplay td").attr("contenteditable","true"); | |
| } | |
| var clipboard = new Clipboard('.btn'); | |
| clipboard.on('success', function(e) { | |
| $("body").addClass("codecopied").delay(2500).queue(function(){ | |
| $(this).removeClass("codecopied").dequeue(); | |
| }); | |
| }); | |
| clipboard.on('error', function(e) { | |
| console.log(e); | |
| }); | |
| $('.codecopiedalert').click(function() { | |
| $('body').removeClass("codecopied"); | |
| }); | |
| // THIS IS TO MAKE THE TABLE EDITABLE | |
| var $TABLE = $('#table'); | |
| var $BTN = $('#export-btn'); | |
| var $EXPORT = $('#export'); | |
| $('.table-add').click(function () { | |
| var $clone = $TABLE.find('tr.hide').clone(true).removeClass('hide table-line'); | |
| $TABLE.find('table').append($clone); | |
| }); | |
| $('.table-remove').click(function () { | |
| $(this).parents('tr').detach(); | |
| }); | |
| $('.table-up').click(function () { | |
| var $row = $(this).parents('tr'); | |
| if ($row.index() === 1) return; // Don't go above the header | |
| $row.prev().before($row.get(0)); | |
| }); | |
| $('.table-down').click(function () { | |
| var $row = $(this).parents('tr'); | |
| $row.next().after($row.get(0)); | |
| }); | |
| // A few jQuery helpers for exporting only | |
| jQuery.fn.pop = [].pop; | |
| jQuery.fn.shift = [].shift; | |
| $BTN.click(function () { | |
| var $rows = $TABLE.find('tr:not(:hidden)'); | |
| var headers = []; | |
| var data = []; | |
| // Get the headers (add special header logic here) | |
| $($rows.shift()).find('th:not(:empty)').each(function () { | |
| headers.push($(this).text().toLowerCase()); | |
| }); | |
| // Turn all existing rows into a loopable array | |
| $rows.each(function () { | |
| var $td = $(this).find('td'); | |
| var h = {}; | |
| // Use the headers from earlier to name our hash keys | |
| headers.forEach(function (header, i) { | |
| h[header] = $td.eq(i).text(); | |
| }); | |
| data.push(h); | |
| }); | |
| // Output the result | |
| $EXPORT.text(JSON.stringify(data)); | |
| }); | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.7.1/clipboard.min.js"></script> |
| $leftsize: 250px; | |
| #maincont {padding-top: 48px;} | |
| //INFO DISPLAY | |
| #infodisplay {background: rgba(0,0,0,0.6); position: relative; padding: 48px 48px; | |
| padding-top: 52px;} | |
| #infodisplay ul{color: #fff; | |
| padding: 0; margin: 0;} | |
| #infodisplay h3 { | |
| margin: 0; | |
| color: #fff; | |
| background: #000000; | |
| background: -webkit-linear-gradient(to right, #434343, #000000); | |
| background: linear-gradient(to right, #434343, #000000); font-weight: normal; | |
| position: absolute; width: 100%; top: 0; left:0; | |
| text-align: center; padding: 6px; | |
| } | |
| *{font-family: 'Montserrat', sans-serif; | |
| -webkit-box-sizing: border-box; | |
| -moz-box-sizing: border-box; | |
| box-sizing: border-box; | |
| } | |
| .clear {clear: both; float: none;} | |
| span.label {position: relative; bottom: 6px;} | |
| .material-icons { | |
| font-family: 'Material Icons'; | |
| font-weight: normal; | |
| font-style: normal; | |
| font-size: 24px; /* Preferred icon size */ | |
| display: inline-block; | |
| line-height: 1; | |
| text-transform: none; | |
| letter-spacing: normal; | |
| word-wrap: normal; | |
| white-space: nowrap; | |
| direction: ltr; | |
| color: #fff; | |
| /* Support for all WebKit browsers. */ | |
| -webkit-font-smoothing: antialiased; | |
| /* Support for Safari and Chrome. */ | |
| text-rendering: optimizeLegibility; | |
| /* Support for Firefox. */ | |
| -moz-osx-font-smoothing: grayscale; | |
| /* Support for IE. */ | |
| font-feature-settings: 'liga'; | |
| } | |
| a.material-icons {text-decoration: none;} | |
| body{background: #1e88e5; margin: 0;} | |
| h1, h2 {color: #fff; font-weight: normal; text-align: center; background: rgba(255,255,255,0.1); margin: 0; padding: 12px;} | |
| h2 {color: #fff; background: #000000; | |
| background: -webkit-linear-gradient(to right, #434343, #000000); | |
| background: linear-gradient(to right, #434343, #000000); | |
| } | |
| .container {max-width: 1170px; width: 100%; display: block; margin: 0 auto; box-sizing: border-box; padding: 12px;} | |
| .per50 {float: left; display: block; width: 50%; box-sizing: border-box; padding: 24px;} | |
| #tablecode {background: #fff; display: block; min-height: $leftsize; margin: 0; padding: 24px; max-height: 200px; overflow-y: scroll; } | |
| // SIZE CHOOSER | |
| .SizeChooser { | |
| margin: 5px 10px 5px 10px; | |
| position: relative; | |
| } | |
| .SizeChooser table { | |
| border-collapse: separate; | |
| border-spacing: 3px; | |
| } | |
| .SizeChooser td { | |
| cursor: pointer; | |
| border: 1px #ccc solid; | |
| height: 10px; | |
| min-width: 10px; | |
| line-height: 10px; | |
| } | |
| .SizeChooser-selected { | |
| border: 1px #333 solid !important; | |
| } | |
| .SizeChooser-hover { | |
| background-color: #DEF; | |
| } | |
| .SizeChooser form span { | |
| background-color: #fff; | |
| border: 1px #ccc solid; | |
| width: 30px; | |
| display: inline-block; | |
| } | |
| .SizeChooser form { | |
| margin: 5px 0 0 3px; | |
| } | |
| //.tschide {display: none;} | |
| #tablepreview #sizer {display: none;} | |
| #tablepreview.showsizer #sizer {display: block;} | |
| #tablepreview #captioner {display: none;} | |
| #tablepreview.showcaptioner #captioner {display: block;} | |
| #tablepreview #headerer {display: none;} | |
| #tablepreview.showheaderer #headerer {display: block;} | |
| .topbar {background: rgba(0,0,0,0.2); box-sizing: border-box; padding: 0px 0px; color: #fff; width: 100%; display: block;} | |
| .topbar form { | |
| float: right; | |
| line-height: 20px; | |
| font-size: 18px; | |
| padding: 6px 12px; | |
| } | |
| span.option { display: block; border-right: 1px solid #1a548a; float: left; | |
| } | |
| .option a {font-size: 24px; padding: 6px 12px;} | |
| .option a:hover {background: rgba(0,0,0,0.2);} | |
| .option a .label {font-size: 18px;} | |
| #tableselector { | |
| table, th, td { | |
| border: 1px solid black; | |
| border-collapse: collapse; | |
| } | |
| } | |
| #tablepreview {position: relative;} | |
| #sizer, #headerer {position: absolute; top: 39px; background: #0e385d; width: 100%; height: $leftsize;} | |
| #headerer {box-sizing: border-box; padding: 12px; color: #fff;} | |
| #captioner {position: absolute; top: 39px; background: #0e385d; width: 100%; box-sizing: border-box; padding: 24px; height: $leftsize;} | |
| #captioner textarea {max-width: 100%; width: 100%;} | |
| .table-bordered>tbody>tr>td, .table-bordered>tbody>tr>th, .table-bordered>tfoot>tr>td, .table-bordered>tfoot>tr>th, .table-bordered>thead>tr>td, .table-bordered>thead>tr>th { | |
| border: 1px solid #ddd; | |
| } | |
| .table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th { | |
| padding: 8px; | |
| line-height: 1.42857143; | |
| vertical-align: top; | |
| border-top: 1px solid #ddd; | |
| } | |
| caption { | |
| padding-top: 8px; | |
| padding-bottom: 8px; | |
| color: #777; | |
| text-align: left; | |
| } | |
| .table-bordered { | |
| border: 1px solid #ddd; | |
| border-collapse: collapse; | |
| } | |
| .table { | |
| width: 100%; | |
| max-width: 100%; | |
| margin-bottom: 20px; | |
| } | |
| .table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th { | |
| padding: 8px; | |
| line-height: 1.42857143; | |
| vertical-align: top; | |
| border-top: 1px solid #ddd; | |
| } | |
| #tabledisplay {background: #fff; display: block; min-height: 50vh; font-family: 'Open Sans',sans-serif;} | |
| .floatleft {padding-top: 0;} | |
| th { | |
| text-align: left; | |
| } | |
| caption { | |
| padding-top: 8px; | |
| padding-bottom: 8px; | |
| color: #777; | |
| text-align: left; | |
| } | |
| .copybtn .material-icons {position: relative; top: 6px; right: 3px;} | |
| .copybtn {background: #ff5722; border: 0; outline: 0; width: 100%; display: block; color: #fff; padding: 3px 12px 11px 12px; font-size: 16px; background: grey; color: lightgray; opacity: 0.7;} | |
| .copybtn:hover {cursor: not-allowed;} | |
| .coderdy .copybtn {background: #ff5722; color: #fff; opacity: 1.0;} | |
| .coderdy .copybtn:hover {cursor: pointer; background: #ff6939;} | |
| .codecopiedalert {display: block; position: fixed; top: 50%; left: 50%; width: 400px; height: 180px; background: #abff81; transform: translateY(-50%) translateX(-50%); z-index: 99; font-size: 24px; font-weight: bold; text-align: center; box-sizing: border-box; padding: 24px; border-radius: 20px; box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);} | |
| .codecopiedalert .material-icons { color: black; font-size: 72px; display: block; margin-bottom: 12px;} | |
| .codecopiedalert {display: none;} | |
| .codecopied .codecopiedalert {display: block;} | |
| #tabledisplay button {display: inline-block; margin-left: 20px; background: #6dbd45; outline: 0; border: 0; font-size: 18px; padding: 6px 12px; color: #000;} | |
| #tabledisplay button:hover {background: lighten(#6dbd45,10%); cursor: pointer;} | |
| #tabledisplay .material-icons {color: #000; font-size: 20px; line-height: 18px; position: relative; right: 3px; top: 3px;} | |
| .codeupdated {} | |
| @-webkit-keyframes demo { | |
| 0% { | |
| } | |
| 100% { | |
| background: #6dbd45; | |
| } | |
| } | |
| .codeupdated #tablecode { | |
| -webkit-animation-name: demo; | |
| -webkit-animation-duration: 150ms; | |
| -webkit-animation-iteration-count: 1; | |
| -webkit-animation-timing-function: ease-in-out; | |
| } | |
| // caption styling | |
| caption.heading { | |
| background-color: #002649; | |
| border: none; | |
| border-top: none; | |
| color: #FFF; | |
| border-radius: 0; | |
| text-indent: 12px; | |
| } |