All shared code should have written documentation to show what it can be used for and what the idea behind it is. Users should at least be able to get a high-level understanding of what they are using, what they’re using it for, and why.
On the web, we have many, many different ways of writing documentation. However, one thing almost all of them have in common is that they rely on Markdown or some variation of it.
And it’s no surprise, because Markdown is supported practically everywhere (VS Code, Atom, GitHub, GitLab, Dev.to, npm, etc.)
In this case, you will mostly share code snippets that people will need to run in their own projects, in which case traditional static site generators like Docusaurus, VuePress, Gatsby, et al work great. All of them have full support for Markdown and allow you to easily create beautiful documentation pages with code snippets/highlighting, and more.
And frankly, if that is your use case, almost everything you need should be possible with those tools, as long as you feel comfortable with the ecosystem/framework.
In this context, users probably do expect a live demo to see all the different options of your component in action. So pure Markdown is usually not enough, as we now want to actually execute code and insert our working component into our documentation somehow. This would require specialized handling for each framework.
For Vue, as an example, you can use VuePress, which auto-registers all Vue components in a certain folder. Then you can use as normal HTML tags since Markdown supports HTML.
.
└─ .vuepress
└─ components
├─ demo-1.vue
For React, you can use MDX, which extends Markdown with JSX support. MDX is available via multiple tools like Gatsby, Docz, Storybook, etc.
import { Chart } from '../components/chart'
# Here’s a chart
The chart is rendered inside our MDX document.
What all these specialized tools have in common is that they require a specific build-tooling setup to work. For web components, none of that is actually needed. Markdown already allows for HTML. The only missing piece is how to load a web component through JavaScript.
The primary goals are to:
The fundamental idea seems almost too simple to be true. We enhance a code fence block with additional metadata js script
.
```js script
import './my-component.js';
# This is my component
<my-component></my-component>
And that’s it!
Alright, enough talk,
mdjs hooks into remark and extracts all those tagged js
blocks. In the end, HTML and JavaScript are available separately.
{
html: '<h1>This is my component</h1><my-component></my-component>',
jsCode: "import './my-component.js';"
}
It can then be combined/processed by any tool to create an actual documentation page.
The process looks like this:
js script
and separate it from Markdown.mdjs script transform
Here’s a link to the animation as slides.
This already is powerful enough to directly include JavaScript and render web components with attributes.
Now that we can execute JavaScript within our Markdown, this opens the door for more advanced features.
Our first step is to create another enhanced JavaScript code block, namely js story
. From this code block, you can export a function to be executed on-demand:
```js script
import './my-component.js';
# This is my component
```js preview-story
export const demo = () => `<my-component header="from attribute"></my-component>`
If you want to add a border around and a button to show/hide the actual source code, you can use js preview-story
.
What you get looks something like this:
{
html: '<h1>This is my component</h1><my-component></my-component>',
jsCode: "import './my-component.js';",
stories: [
key: 'demo',
name: 'demo',
code: 'export const demo = () => `<my-component header="from attribute"></my-component>`',
]
}
Under the hood, this adds an extra step to the processing:
js script
and separate from Markdown.js story
and js preview-story
and separate from Markdown.mdjs-preview
at its place.This is all the information we need to create full JavaScrip and demo capable pages purely from Markdown.
By default, mdjs takes it a small step further by supporting an actual template system — namely lit-html.
```js script
import './demo-wc-card.js';
import { html } from 'lit-html';
# This is my component
```js story
export const demo = () => html`
<demo-wc-card header="HEADER"></demo-wc-card>
`;
mdjs story transform
Here’s a link to the animation as slides.
Here’s another playground mimicking a full documentation page: Link to editable demo.
Once all this meta-information is available, you can render a specific docs page.
It basically comes down to generating this code, which assigns the demo function to the actual web component:
const stories = [{ key: 'demo', story: demo, code: demo }];
for (const story of stories) {
const storyEl = rootNode.querySelector(`[mdjs-story-name="${story.key}"]`);
storyEl.story = story.story;
storyEl.code = story.code;
}
All of this happens under the hood for you.
Here I’ll show you how you can create a GitHub like Markdown view for all your local Markdown files, including live demos.
es-dev-server screenshot
es-dev-server
as a dependency by running npm i -D es-dev-server
.package.json
:"scripts": {
"start": "es-dev-server",
}
es-dev-server.config.js
in the root of your repo.const { mdjsTransformer } = require('@mdjs/core');
module.exports = {
nodeResolve: true,
open: 'README.md',
watch: true,
responseTransformers: [mdjsTransformer],
};
After executing npm run start
, you can happily browse your live documentation via http://localhost:8000/README.md.
You can see an example setup in the demo-wc-card repo.
If you want to work on individual components or get a list of all demos, you can use Storybook.
storybook screenshot
npm i -D @open-wc/demoing-storybook
.package.json
:"scripts": {
"storybook": "start-storybook",
}
.storybook/main.js
to load Markdown files:module.exports = {
stories: ['../README.md', '../docs/**/*.md'],
esDevServer: {
nodeResolve: true,
watch: true,
open: true,
},
};
export default {
title: 'My Group/My Awesome Component',
};
And just like that, you are good to go. No additional changes to any files are needed; a plugin will take care of everything by converting your Markdown files to support Storybook’s MDX format.
For more detailed information, please see https://open-wc.org/demoing-storybook/.
Since GitHub supports Markdown out of the box, we can take things even further by using mdjs.
github screenshot
As it’s not supported by GitHub directly, you will need a Chrome extension called mdjs-viewer.
Almost looks like black magic, huh? All you did was install a Chrome extension and suddenly GitHub got superpowers.
All that you need is to have some Markdown files with the correct code fence blocks, and have your code up and running on unpkg.com.
How does it actually work?
The extension detects which GitHub page you are on. If it finds a Markdown file or an issue with mdjs code, then it adds a Show Demo button to activate it. If you click the button, it will start gathering all the needed info:
package.json
.unpkg.com
imports.unpkg.com
and the name of the package.json + relative path for it.Some of the tasks are more complicated and require some extra work to make it secure, but in essence, that’s it.
With that, you can put documentation with live examples on GitHub. Even issues with demos showing the actual error in the code are possible.
That sure sounds like a hell of a tool to improve your documentation and issue reproduction, doesn’t it? Especially as the readme and issue content still remain useful even without the extension.
For more detailed information please see https://github.com/open-wc/mdjs-viewer.
It’s fully supported by this awesome online editor.
webcomponent.dev screenshot
You can directly edit your documentation, demos, and code in the browser.
webcomponent.dev screenshot
You can start directly with documentation, as in the screenshot above. Of even better, you can use it in every Markdown file or README.md
.
Give it a go and document your components in all their glory.
All the demo links are from webcomponents.dev.
Please check the official documentation page at https://open-wc.org/mdjs/.
There you have it — mdjs is a format that can be shown in many different ways. It is your single source of truth for good-looking documentation everywhere. Be it locally, a published Storybook, on GitHub or npm, it always looks good, even if there is no direct support for it, but when possible, it will become interactive with demos through progressive enhancement.
Now go out there and write good documentation for your components!
Thank you for reading!
#markdown #javascript #github #chrome extension #programming