Pure JavaScript library for converting HTML into valid Markdown





GitHub Stars



Last Commit

4yrs ago






Size (min+gzip)



Type Definitions




Package has been moved to Europa:



Europa is a pure JavaScript library for converting HTML into valid Markdown.

Demo Build Status Dev Dependency Status License Release


Install using the package manager for your desired environment(s):

$ npm install --save europa
# OR:
$ bower install --save europa

If you want to simply download the file to be used in the browser you can find them below:

Check out node-europa if you want to install it for use within Node.js.


<!DOCTYPE html>
    <p class="lead">We &hearts; <b>Europa</b>!</p>

    <textarea id="html"></textarea>
    <textarea id="markdown"></textarea>

    <script src="/path/to/europa.js"></script>
      (function() {
        var europa = new Europa();
        var html = document.getElementById('html');
        var markdown = document.getElementById('markdown');

        html.addEventListener('input', function() {
          markdown.value = europa.convert(html.value);

Open up demo.html in your browser to play around a bit.


Simply create an instance of Europa and you've done most of the work. You can control many aspects of the HTML to Markdown conversion by passing the following options to the constructor:

absoluteBooleanWhether absolute URLS should be used for anchors/imagesfalse
baseUriStringThe base URI for the window (ignored in environments where the base URI cannot be changed)Environment-specific
inlineBooleanWhether anchor/image URLs are to be inserted inlinefalse
var europa = new Europa({
  absolute: true,
  baseUri: '',
  inline: true

The baseUri option is ignored by environments where the base URI cannot be changed (e.g. browsers), however, some environments may support it and, in those cases, a default base URI is also provided. See the documentation for the implementation for more details on their default base URI.


Converts the specified html into Markdown.

html can either be an HTML string or a DOM element whose HTML contents are to be converted into Markdown.

var europa = new Europa();

europa.convert('<blockquote>This <i>is</i> great!</blockquote>');
//=> "> This *is* great!"
//=> "We ♥ **Europa**!"

var div = document.createElement('div');
div.innerHTML = 'Please keep my <span style="display: none">treasure</span> secret safe...';

//=> "Please keep my secret safe..."


Releases the window being used.

Some environments use virtual windows and, since each Europa instance will have its own window, calling this method when you're done with the instance can help to free up resources.

However, a new window will be used if you attempt to call convert on the same instance. So you don't have to worry about creating lots of instances, just ensuring that you release them after its done its job to free up resources.

Windows are only ever created when convert is called and not when you instantiate Europa!

You may well want to keep the window "open" in order to speed up consecutive conversions (e.g. in an iteration).

var europa = new Europa({ inline: true });

var input = [
  '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit...</p>',
  '<p>Etiam sed felis ligula. Maecenas sit amet tristique risus...</p>',
  '<p>In dictum consequat nulla at lobortis...</p>'
var output = {
  return europa.convert(html);


// ...

europa.convert('Wow! <a href="">Europa</a> is awesome!');
//=> "Wow! [Europa]( is awesome!"

Other environments (e.g. browsers) should never have to worry about calling this method.


Europa is fully pluggable and is packed with built-in plugins in order to get full support for basic Markdown. It enables the creation of external plugins to further extend Europa's capabilities to support extended Markdown syntax or even new HTML elements should they not be added to Europa quick enough for you.

The predefined plugins are included in Europa Core for now, however, the plan is to externalize all of these as well, while keeping them as defaults. The hope is that this will continue to make them easier to maintain and make Europa more modular.

The API for plugins is simple on a high level, but you'll need to get to grips with the internal API to understand what you can really do:

var ExamplePlugin = Europa.Plugin.extend({
  after: function(conversion, context) { /* ... */ },
  afterAll: function(conversion) { /* ... */ },
  before: function(conversion, context) { /* ... */ },
  beforeAll: function(conversion) { /* ... */ },
  convert: function(conversion, context) { /* ... */ },
  getTagNames: function() { /* ... */ }

Europa.register(new ExamplePlugin());

Your best bet is to look at how other plugins work.

All plugins should be responsible for registering themselves when loaded as to minimize the work required by you, in order to use them. Since multiple plugins could support the same tag(s), the load order is important as the last plugin loaded that declares support for a tag, will be the one that's used. Be wary of overriding tags supported by built-in plugins and consider whether its something that should be part of the original plugin. If so, open a pull request!

A good practice for naming plugin packages is europa-plugin-FRIENDLY_TAG_NAME. For example; europa-plugin-anchor and not europa-plugin-a or europa-plugin-link (which could be confused with the <link> element). Each plugin should have a shared goal.

The plugin implementation class -- not registered instance -- should always be exported by each plugin. This is to allow others to extend and take advantage of the OOP design.


Europa also has the concept of a "preset", which is essentially a bundle of plugins. In fact, all of the built-in plugins are provided by a default preset internally.

A preset simply imports a collection of plugins, all of which register themselves with Europa automatically.

A good practice for naming preset packages is europa-preset-FRIENDLY_GOAL_NAME. For example; europa-preset-atlassian could be used to register plugins that converts HTML to Atlassian Wiki Markup. Each plugin should have a shared goal.

In theory, a preset could be made up of multiple presets.

Migrating from older versions

If you've been using an older major version and would like details on what's changed and information on how to migrate to the latest major release below:


If you have any problems with Europa or would like to see changes currently in development you can do so here. Core features and issues are maintained separately here.


If you want to contribute, you're a legend! Information on how you can do so can be found in We want your suggestions and pull requests!

A list of Europa contributors can be found in


See for more information on our MIT license.

Copyright !ninja

Rate & Review

Great Documentation0
Easy to Use0
Highly Customizable0
Bleeding Edge0
Responsive Maintainers0
Poor Documentation0
Hard to Use0
Unwelcoming Community0
No reviews found
Be the first to rate


No alternatives found


No tutorials found
Add a tutorial