<!--
  canonical-url: https://www.avonture.be/blog/markdown-xls2md
  published:     2024-12-08
  This is a static plain-Markdown mirror generated at build time.
  Visit the canonical URL above for the fully rendered page, with images and interactive components.
-->

# Markdown - Convert Excel ranges to Markdown tables

> Easily convert Excel ranges into clean Markdown tables with the XLS2MD online tool. Just copy your cells and paste to generate the code and a live HTML preview.

---
![Markdown - Convert Excel ranges to Markdown tables](/img/v2/markdown.webp)

**TL;DR**

This article introduces XLS2MD (xls2md.avonture.be, source on GitHub), a free online tool that converts a copied Excel range directly into a Markdown table: select cells in Excel, copy, paste into the site, and get instant Markdown output.

See also [Markdown - Convert CSV to Markdown tables](/blog/markdown-csv2md). For a much broader conversion need — full Word, PDF or PowerPoint documents rather than just a range — see [Markitdown - Convert files and MS Office documents to Markdown](/blog/markitdown).

I'm a big fan of Markdown for my documentation, and from time to time I have to convert a range in Excel into a table to copy and paste into my documentation. *Documentation which, most of the time, is then rendered with [Quarto](/blog/docker-quarto).*

Years ago, I found this repo <https://github.com/jonmagic/copy-excel-paste-markdown> and it was the trigger for creating an online application in VueJS to make the magic happen.

In practical terms, I open my Excel file, select a range (a series of columns and rows) f.i. `$A$1:$J$50`, press `CTRL`+`C` on the keyboard, switch to my [Markdown - Convert Excel ranges to Markdown tables](https://xls2md.avonture.be/) website, press `CTRL`+`V` and the table is converted.

It's ... magical

Here is a demo:

![Markdown - Convert Excel ranges to Markdown tables](./images/demo.gif)

## Source code

You can find it on Github too: <https://github.com/cavo789/marknotes_xls2md/tree/master>.

**index.php**

```php
<?php

// cspell:disable

declare(strict_types = 1);

/*
 * AUTHOR : AVONTURE Christophe
 *
 * Written date : 3 october 2018
 *
 * Excel raw table to markdown converter
 * Simply copy, from Excel, a table and paste here to convert
 * table to markdown
 *
 * The javascript has been written by `Jonathan Hoyt` and available on GitHub:
 * https://github.com/jonmagic/copy-excel-paste-markdown.
 *
 * JS script updated to:
 * - Call marked.js (https://www.npmjs.com/package/marked) to render the table from markdown
 *         to html
 * - Add bootstrap class to the rendered table
 *
 * Last mod:
 * 2019-01-01 - Abandonment of jQuery and migration to vue.js
 */

define('REPO', 'https://github.com/cavo789/marknotes_xls2md');

// Get the GitHub corner
$github = '';
if (is_file($cat = __DIR__ . DIRECTORY_SEPARATOR . 'octocat.tmpl')) {
    $github = str_replace('%REPO%', REPO, file_get_contents($cat));
}
?>

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8"/>
        <meta name="author" content="Christophe Avonture" />
        <meta name="robots" content="noindex, nofollow" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=9; IE=8;" />
        <title>Marknotes - XLS2MD - Convert Excel raw table to Markdown table</title>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
        <style>
            textarea {
                margin-top:10px;
                font-family:Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace;
            }
            details {
                margin: 1rem;
            }
            summary {
                font-weight: bold;
            }
            .form-control {
                padding: none;
                font-size: 0.8em;
            }
        </style>
    </head>
    <body>
        <?php echo $github; ?>
        <div class="container">
            <div class="page-header"><h1>Marknotes - XLS2MD</h1></div>
            <div class="container" id="app">
                <div class="form-group">
                    <how-to-use demo="https://raw.githubusercontent.com/cavo789/marknotes_xls2md/master/image/demo.gif">
                        <ol>
                            <li>In your Excel worksheet, select a range like f.i.
                                $A$1:$H:$25 (first row need to contains column's headings).</li>
                            <li>Press <kbd>CTRL</kbd><kbd>C</kbd></li>
                            <li>In this form, click in the text area here below</li>
                            <li>Press <kbd>CTRL</kbd><kbd>V</kbd></li>
                        </ol>
                        <p>The copied data will be immediately converted to a markdown table
                            and a HTML preview will be rendered.</p>
                        <p>Adjust the markdown syntax if needed and copy/paste into your
                            notes.</p>
                    </how-to-use>
                    <label for="editor">Simply copy, from Excel, a table and paste here to convert
                        table to markdown.</label>
                    <textarea class="form-control" rows="5" v-model="editor" name="editor" @change="onChange" @paste="onPaste"></textarea>
                </div>
                <hr/>
                <div v-if="Markdown!==''">
                    <h2 id="markdown">Markdown code <small style="font-size:0.4em"><a href="#html">See HTML rendering</a></small></h2>
                    <pre v-html="Markdown"></pre>
                    <hr/>
                </div>
                <div v-if="HTML!==''">
                    <h2 id="html">HTML rendering <small style="font-size:0.4em"><a href="#markdown">See Markdown code</a></small></h2>
                    <pre v-html="HTML"></pre>
                    <hr/>
                </div>
            </div>
        </div>
        <script src="https://unpkg.com/vue@2"></script>
        <script src="https://unpkg.com/marked@0.3.6"></script>
        <script type="text/javascript">

            function columnWidth(rows, columnIndex) {
                return Math.max.apply(
                null,
                rows.map(function(row) {
                    return row[columnIndex].length;
                })
                );
            }

            function getMarkdown(data) {
                var rows = data.split(/[\n\u0085\u2028\u2029]|\r\n?/g).map(function(row) {
                    return row.split("\t");
                });

                var columnWidths = rows[0].map(function(column, columnIndex) {
                    return columnWidth(rows, columnIndex);
                });

                var markdownRows = rows.map(function(row, rowIndex) {
                    // | Name         | Title | Email Address  |
                    // |--------------|-------|----------------|
                    // | Jane Atler   | CEO   | jane@acme.com  |
                    // | John Doherty | CTO   | john@acme.com  |
                    // | Sally Smith  | CFO   | sally@acme.com |
                    return (
                        "| " +
                        row
                        .map(function(column, index) {
                            return (
                            column + Array(columnWidths[index] - column.length).join(" ")
                            );
                        })
                        .join(" | ") +
                        " |"
                    );
                    row.map;
                });

                markdownRows.splice(
                    1,
                    0,
                    "| " +
                        columnWidths
                        .map(function(width, index) {
                            return Array(columnWidths[index]).join("-");
                        })
                        .join(" | ") +
                        " |"
                );

                // Get the markdown representation of the pasted info
                return markdownRows.join("\n");
            }

            Vue.component('how-to-use', {
                props: {
                    demo: {
                        type: String,
                        required: true
                    }
                },
                template:
                    `<details>
                        <summary>How to use?</summary>
                        <div class="row">
                                <div class="col-sm">
                                    <slot></slot>
                                </div>
                                <div class="col-sm"><img v-bind:src="demo" alt="Demo"></div>
                            </div>
                        </div>
                    </details>`
            });

            var app = new Vue({
                el: '#app',
                data: {
                    editor: '',
                    Markdown: ''
                },
                methods: {
                    onChange(event) {
                        this.Markdown = getMarkdown(this.editor);
                    },
                    onPaste(event) {
                        event.preventDefault();
                        var clipboard = event.clipboardData;
                        this.editor = clipboard.getData("text/plain").trim();
                        this.Markdown = getMarkdown(this.editor);
                    }
                },
                computed: {
                    HTML() {
                        if (this.Markdown == '') {
                            return '';
                        }
                        // Call marked() to convert the MD string into a HTML table
                        var mdTable = marked(this.Markdown, { sanitize: true });
                        // Add Bootstrap classes
                        mdTable = mdTable.replace('<table>', '<table class="table table-hover table-striped">');
                        return mdTable;
                    }
                }
            });
        </script>
    </body>
</html>
```
