Skip to content

Ridiculously simple markdown displayer - a native web component based on Custom Elements v1 specs to load and display an external MD file

License

Notifications You must be signed in to change notification settings

automician/zero-md

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

93 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GitHub release jsDelivr hits (GitHub)

<zero-md>

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.

Let's get this money

Basic usage via CDN (recommended)

  1. 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>
  1. 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>
  1. Profit!
<!-- Simply set the `src` attribute to your MD file and win -->
<zero-md src="https://www.example.com/my-markdown.md"></zero-md>

Async usage

<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>

Advanced usage

  1. 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>
  1. 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>
  1. 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>
  1. 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>

Instantly publish HTML from Markdown

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 locally

  1. Install via NPM.
npm install --save zero-md
  1. Optionally install webcomponents.js, Prism and Marked if you wish to host them yourself.
npm install --save @webcomponents/webcomponentsjs prismjs marked
  1. 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>

Develop and contribute

  1. Clone the repo.
git clone https://github.com/zerodevx/zero-md.git && cd zero-md
  1. Install dependencies.
npm install && bower install
  1. Start your favourite web server.
python -m SimpleHTTPServer 8000
  1. Run tests from your browser.
http://localhost:8000/test/zero-md_test.html
  1. Lint your code.
npm run lint
  1. And build it if you wish to.
npm run build
  1. Noticed a bug? Have a feature request? Raise an issue.

  2. Or even better, open a PR!

Demo

This page, actually. Or for a more comprehensive example demonstrating the various features, try this.

API

Behavior

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.

Host styles

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>

Default configs

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>
  1. When setting global config, ensure that the window.ZeroMd.config object is defined before importing the <zero-md> element definition.

  2. The following configs are exposed (in camelCase): markedUrl, prismUrl and cssUrls.

Published Attributes

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>

Public Methods

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.

Convenience Events

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.

Themes

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.

Implementation Notes

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!

License

MIT

Version history

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

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 since HTMLImports 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 and prismjs 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 with class="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.

About

Ridiculously simple markdown displayer - a native web component based on Custom Elements v1 specs to load and display an external MD file

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • HTML 54.5%
  • JavaScript 45.5%