Ridiculously simple markdown displayer - a native web component based on Custom Elements v1 specs to load and display an external MD file.
Instantly create beautiful HTML pages from Markdown. Like it isn't easy enough.
While it's already remarkably trivial to render markdown into HTML (Marked) and syntax-highlight (Prism), <zero-md>
does this better, automagically rendering into its own self-contained Shadow DOM container, while encapsulating implementation details into one embarassingly easy-to-use package.
Because web components. All in ~100 lines of code.
- Import webcomponents-loader.js.
<!-- Lightweight client-side loader that feature-detects and load polyfills only when necessary -->
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2/webcomponents-loader.min.js"></script>
Note: It seems there has been a regression in webcomponentsjs
that broke support for Firefox v60
as reported in #19. If you need to support super old Firefoxes, it's recommended to pin webcomponentsjs
to v2.2.10
.
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2.2.10/webcomponents-loader.min.js"></script>
- Import
<zero-md>
web component.
<!-- Load the element definition -->
<script type="module" src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@1/src/zero-md.min.js"></script>
- Profit!
<!-- Simply set the `src` attribute to your MD file and win -->
<zero-md src="https://www.example.com/my-markdown.md"></zero-md>
<head>
...
<script defer src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2/webcomponents-loader.min.js"></script>
<script type="module">
WebComponents.waitFor(() => {
let el = document.createElement('script');
el.src = 'https://cdn.jsdelivr.net/gh/zerodevx/zero-md@1/src/zero-md.min.js';
document.head.appendChild(el);
});
</script>
...
</head>
- Use your own markdown and highlight stylesheets instead.
<!-- Pass in an array of CSS URLs via the `css-urls` attribute in valid JSON format -->
<zero-md
css-urls='["https://example.com/styles/custom-markdown.css", "https://example.com/styles/custom-highlight.css"]'
src="https://example.com/my-markdown.md">
</zero-md>
- Or pass markdown strings directly into the element.
<zero-md>
<!-- Declare `<template>` element as a child of `<zero-md>` -->
<template>
<!-- Wrap your markdown string inside an `<xmp>` tag -->
<xmp>
# `This` is my [markdown](https://example.com)
H~~ell~~o *W*o**r**l***d***!
</xmp>
</template>
</zero-md>
- Or pass your own CSS definitions directly into the element.
<zero-md src="https://example.com/my-markdown.md">
<!-- Declare `<template>` element as a child of `<zero-md>` -->
<template>
<!-- Wrap your own CSS styles inside a `<style>` tag -->
<style>
/* My own markdown styles */
h1 { font-size: 24px; }
p { color: red; }
...
/* My own highlight styles */
code p { color: blue; }
...
</style>
</template>
</zero-md>
- Or put it all together.
<zero-md>
<!-- Declare `<template>` element as a child of `<zero-md>` -->
<template>
<!-- Wrap your CSS styles inside a `<style>` tag -->
<style>
/* My own markdown styles */
h1 { font-size: 24px; }
p { color: red; }
...
/* My own highlight styles */
code p { color: blue; }
...
</style>
<!-- Wrap your markdown string inside an `<xmp>` tag -->
<xmp>
# `This` is my [markdown](https://example.com)
H~~ell~~o *W*o**r**l***d***!
</xmp>
</template>
</zero-md>
Create a beautiful HTML web page from Markdown in literally 1 minute. Copy and paste the below boilerplate code into an empty index.html
file, edit, and it's ready to be served from any static host.
index.html (download)
<!doctype html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Edit your site info here -->
<meta name="description" content="EXAMPLE SITE DESCRIPTION">
<title>EXAMPLE SITE TITLE</title>
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2/webcomponents-loader.min.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@1/src/zero-md.min.js"></script>
<style>
/* Edit your header styles here */
header { font-family: sans-serif; font-size: 20px; text-align: center; position: fixed; width: 100%; line-height: 42px; top: 0; left: 0; background-color: #424242; color: white; }
body { box-sizing: border-box; min-width: 200px; max-width: 980px; margin: 56px auto 0 auto; padding: 45px; }
@media (max-width: 767px) {
header { font-size: 15px; }
body { padding: 15px; }
}
</style>
</head>
<body>
<!-- Edit your Markdown URL file location here -->
<zero-md src="https://example.com/EXAMPLE.md"></zero-md>
<!-- Edit your header title here -->
<header class="header">EXAMPLE HEADER TITLE</header>
<!-- Edit your Github ribbon here (https://github.com/blog/273-github-ribbons) -->
<a href="https://example.com"><img style="position: fixed; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/652c5b9acfaddf3a9c326fa6bde407b87f7be0f4/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6f72616e67655f6666373630302e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_orange_ff7600.png"></a>
</body>
</html>
<zero-md>
works fantastically well for publishing quick project pages, info, news, homepages etc. It doesn't get easier than this.
- Install via NPM.
npm install --save zero-md
- Optionally install webcomponents.js, Prism and Marked if you wish to host them yourself.
npm install --save @webcomponents/webcomponentsjs prismjs marked
- Use locally.
<head>
...
<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
<script>
// Set global configs. Declare before importing `zero-md` element.
// These settings will apply to all instances of `zero-md`.
window.ZeroMd = {
config: {
// Basically, we want to point all library references to our local ones instead.
prismUrl: '/node_modules/prismjs/prism.js',
markedUrl: '/node_modules/marked/marked.min.js',
cssUrls: [
'/styles/my-cool-markdown-theme.css',
'/styles/bling-highlight-colors.css'
]
}
};
</script>
<script type="module" src="/node_modules/zero-md/src/zero-md.js"></script>
...
</head>
<body>
...
<zero-md src="/markdown/my-super-good-post.md"></zero-md>
...
<zero-md src="/markdown/some-nice-testimonials.md"></zero-md>
...
</body>
- Clone the repo.
git clone https://github.com/zerodevx/zero-md.git && cd zero-md
- Install dependencies.
npm install && bower install
- Start your favourite web server.
python -m SimpleHTTPServer 8000
- Run tests from your browser.
http://localhost:8000/test/zero-md_test.html
- Lint your code.
npm run lint
- And build it if you wish to.
npm run build
This page, actually. Or for a more comprehensive example demonstrating the various features, try this.
In order of priority, <zero-md>
first tries to retrieve the markdown string from its <template><xmp>...</xmp></template>
child; if none is defined, <zero-md>
next attempts to retrieve from the URL defined in the src
attribute via ajax.
Likewise, for CSS styles, <zero-md>
first tries to retrieve the styles defined in <template><style>...</style></template>
; if none, <zero-md>
next attempts to retrieve all the external stylesheets defined in the css-urls
attribute array.
By default, each <zero-md>
instance has the following styles applied to itself.
:host {
display: block;
position: relative;
contain: content;
}
These are sensible defaults that should apply to most use-cases and also help normalise behavior across browsers - since the contain
CSS property is only implemented in Chrome. The beauty of web components is that you can easily override these defaults from outside the element to suit your needs.
<style>
#my-element {
display: inline-block;
contain: none;
}
</style>
<zero-md id="my-element" src="example.md"></zero-md>
By default, <zero-md>
loads the (Marked) JS library from CDN here; and the (Prism) JS library from here. These URL locations can be overridden by setting the marked-url
and prism-url
attributes respectively.
For styles, by default the css-urls
attribute contains a list of Github markdown stylesheet from here, and a light-themed highlight stylesheet from here. The defaults can be overridden by setting that attribute with an array of URLs in valid JSON format.
Attribute | Type | Default value |
---|---|---|
marked-url | String | https://cdn.jsdelivr.net/npm/marked@0/marked.min.js |
prism-url | String | https://cdn.jsdelivr.net/npm/prismjs@1/prism.min.js |
css-urls | Array | ["https://cdn.jsdelivr.net/npm/github-markdown-css@2/github-markdown.min.css", "https://cdn.jsdelivr.net/npm/prismjs@1/themes/prism.min.css"] |
These defaults can be overridden globally by setting the ZeroMd.config
global. Note that setting the global config will apply to all instances of <zero-md>
in the document.
<head>
...
<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
<script>
// Set global configs. Declare before importing `zero-md` element.
// These settings will apply to all instances of `zero-md`.
window.ZeroMd = {
config: {
cssUrls: [
'/styles/my-markdown-theme.css',
'/styles/my-highlight-theme.css'
]
}
};
</script>
<script type="module" src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@1/src/zero-md.min.js"></script>
</head>
<body>
...
<!-- So we don't have to repeat `css-urls='["a.css","b.css"]'` over and over again. -->
<zero-md src="https://example.com/markdown/post1.md"></zero-md>
...
<zero-md src="https://example.com/markdown/post2.md"></zero-md>
...
</body>
-
When setting global config, ensure that the
window.ZeroMd.config
object is defined before importing the<zero-md>
element definition. -
The following configs are exposed (in camelCase):
markedUrl
,prismUrl
andcssUrls
.
Attribute | Type | Description |
---|---|---|
src | String | URL location to GET the markdown text file via ajax. |
manual-render | Boolean | If set, disables auto-rendering of this instance. Call the render() function on that instance to start manually. |
marked-url | String | URL of the Marked JS library. |
prism-url | String | URL of the Prism JS library. |
css-urls | String | An array of stylesheet URLs to apply to this instance in valid JSON. |
no-shadow | Boolean | If set, renders and stamps this instance into Light DOM instead. Please know what you're doing. |
For css-urls
, please ensure that the value is an Array in valid JSON format. For example:
<!-- Note the double-quotes ""! -->
<zero-md css-urls='["./styles/markdown-stylesheet.css", "./styles/highlight-stylesheet.css"]'></zero-md>
Method | Parameters | Description |
---|---|---|
render() | none | Starts the markdown conversion and stamps into DOM. |
By default, each instance automatically calls the render()
method on start-up. To prevent this behavior, add the attribute manual-render
to your <zero-md>
element, and manually call this method to begin rendering. For example:
<zero-md id="my-element" manual-render src="example.md"></zero-md>
...
<script>
let el = document.querySelector('#my-element');
el.render();
</script>
Note that if changes are made to <zero-md>
attributes or <template>
children dynamically, call the render()
method on that instance to force a re-render.
Event Name | Description |
---|---|
zero-md-ready | Fired after <zero-md> is connected. |
zero-md-marked-ready | Fired after Marked JS library has loaded. |
zero-md-prism-ready | Fired after Prism JS library has loaded. |
zero-md-rendered | Fired after markdown converted, syntax highlighted, and contents stamped to DOM. |
Google it! Or try here, here or here.
Themes are just standard CSS stylesheets that can be applied to an instance of <zero-md>
. One of the coolest feature of web components is encapsulation - so these styles will not bleed out of its shadow DOM and affect the rest of the document.
Load your theme stylesheets by setting the css-urls
attribute. Check out the published attributes API.
The <xmp>
tag is deprecated!
In short, don't worry about it. Though the tag has been deprecated for 20 years, browser vendors (generally) try their hardest not to break the web. It is still implemented in modern browsers today. It's the only tag that suits such purpose, by allowing true pre-formatted content to be written as-is within the confines of the HTML document without endless escaping. Use it.
v1.x is completely different!
Yes it is. v1.x is absolutely breaking and not compatible with previous versions. Code is entirely re-written based on the new Custom Elements v1 specs with lots of ES6 goodness. It runs natively in modern browsers and is incredibly light and performant. This serves as a great showcase for how far we've come with Custom Elements, Web Components, its ideas, usage and patterns.
Anchor links support added!
Referencing this Github issue, a shout-out to @alexroseb for raising this. So the native browser handler for an <a>
link that points to an element id
doesn't pierce through shadow DOM - and I missed it. It's a feature, not a bug. Really!
MIT
v1.3.3 - 2020-01-07
- Fixed typo that broke C syntax highlighting - thanks @TheUnlocked! (ref: PR#21)
- Add usage note on webcomponentsjs polyfill regression in FFv60. (ref: #19)
- Update dependencies.
v1.3.2 - 2019-07-31
- Maintenance update of dev dependencies.
v1.3.1 - 2019-04-22
- Actually build for v1.3.1 (fixes #15).
- Automate the chore of version bumping else I keep missing things.
v1.3.0 - 2019-04-21
- Exposes the
ZeroMd.config
global to set default values applying to all instances of<zero-md>
in the document. (Ref: PR#12) - thanks @bennypowers! - Update default host CSS to help normalise behavior across browsers. Fixes #13 - thanks @bennypowers!
- Publish on NPM to support modern workflows per #11.
v1.2.2 - 2019-02-03
- Really fix meta-click links #8, thanks @ernsheong!
v1.2.1 - 2019-01-31
- Patch anchor links to support CMD+clicks.
v1.2.0 - 2018-11-26
- The community-agreed standard pattern of importing webcomponents is now via ES Modules. Consequently,
HTMLImports
will soon be deprecated from Chrome. Don't worry - your old code still works sinceHTMLImports
falls-back to polyfill. For better performance however, do update your existing code to load using ES Modules instead. - Update all CDN links to jsDelivr and pin with semver.
- Per #6, use
getElementById
instead to prevent DOM exception error messages.
v1.1.0 - 2018-05-17
- Add anchor links feature.
- Update boilerplate to correct layout in Firefox.
- Update CDN links for
markedjs
to v0.3.19 andprismjs
to v1.14.0.
v1.0.0 - 2018-04-06
- Breaking changes, major release and incompatible with earlier v0.x versions.
- Completely re-written, updated to 2018 patterns, removes the need for Polymer and runs natively for a no-sugar, low-fat diet. Please read the docs and upgrade accordingly.
v0.2.0 - 2015-10-23
- Breaking changes and is incompatible with earlier versions.
- Remove
style-module
usage - instead mandate a child container element withclass="md-html"
for simpler styling. - Remove
<iron-ajax>
dependency. - Remove
zero-md-file-loaded
convenience event. - Add
reload()
method to dynamically reload content inside<xmp>
tags. - Completely rewrite rendering algorithm. Smaller, lighter and faster!
v0.1.1 - 2015-09-04
- Minor patches to default markdown theme.
v0.1.0 - 2015-09-01
- Initial commit.