Notebook Is A Better Readme

Source code, repo, published version

A lot of the times newcomers to open source projects are kindly asked to contribute to readme or documentation before they can do any real work. Same thing starting a new job. Many smaller projects get their readme as an afterthought. We also tend to forget to keep readme/documentation up-to-date rendering them even more confusing.

I'd been writing my project for over a year and hoping to get help, buy-in, and collaboration. Then I realized that I hadn't updated my Readme since starting out, and it was out of date, and, frankly sucked. It was not convincing, and it was the first thing that devs saw when assessing my project!


This quote comes from a Hacker News thread about Readme Driven Development (great read, by the way!). The name implies you should write your readme before writing any code. I'd like to extend that idea for things that work inside browser.

Readme can execute the code it's describing

What if reader could interact with the code, try different modes and values while following the general narrative of the document? Basic example:



Draw is a library for drawing shapes of different colors. It can draw squares, triangles and circles in red, green and blue.


npm install my-draw-library



(red, green, or blue) ...


(triangle, circle or square) ...


Grab the code below to draw the shape you've selected.

import draw from "my-draw-library";

draw({ color: "...", shape: "..." });

This approach should work for most libraries that have text or graphic output. Too often I find myself installing an npm package, going through all the instructions only to find that it's not what I need. I only wish I learned it sooner! In case GitHub I'm already looking at a page rendered inside the browser so it could run the package code along with proper sandboxing.

Now, GitHub offers GitHub Pages with Jekyll or other static-site generator but I see two major drawbacks here:

Good thing about GitHub readmes is that they are absolutely consistent in how they look and feel and their content to some extent. To illustrate the problem please take a look at the Prism.js' GitHub Pages. (I love the library, don't mean to pick at it in any way). I was trying to find how to highlight the DOM node with the import statement above but that page made me feel right away that it won't be easy to find what I need. Instead I want to know where to look before I even open the page. It should be noted that setting up static site generator is extra work not many are willing and able to do.

Prism.js GitHub Pages

On the other hand their is lacking in favor or the GitHub Pages site, I assume.

Prism.js readme

Can we have the best of both worlds?



Prism is a lightweight, robust, and elegant syntax highlighting library. It's a spin-off project from Dabblet.

You can learn more on

Why another syntax highlighter?

More themes for Prism!


Theme: ...






There is no standard way to write such a readme/documentation page. We didn't always have and GitHub Flavored Markdown, yet today it is such a commodity no one notices the improvement it brought at a very low cost to maintainers.

Now, I've been working on a tool combining notebook, spreadsheet and "app-builder" type of thing, pretty far from the wants I've described above, when one day I found myself writing readmes precisely this way! The page you're reading right now is Markdown with that extra syntax. Check this out:

// Demo code for Prism.js
{ theme = select({ value: "prism", options: themes })}

{ applyTheme(theme) }

{ value = input({ value: 'const prismjs = test === 42 || 43', size: 4 }) }

{ highlight(value) }

Expressions inside curly braces are spreadsheet cells so any changes in their state are applied on any depending nodes. It is like Excel without grid and addresses. select and input functions are simple wrappers around html select and input tags, and highlight is a Prism.js wrapper component. This file you're reading is, by Ellx convention it shares scope with index.js so all of the mentioned functions are being exported by it.

These few ideas combined together provide a very concise way to write readme and write library code in general. It becomes the sort of instant TDD while the development process is being documented in the readme as you go along. I tried this approach with headlong recently. First, describe intent, add the demo code as if it's a test.


This library will export function mySum returning sum of its arguments


Then write a function.


This library exports function mySum returning sum of its arguments:

1 + 2 + 3 = ...

{ mySum2(1, 2, 3) }

Then add controls to play around, search for edge cases, or combine with other functions. Rinse and repeat. (actually discoved a bug in a one-line sum function 🤦‍♀️)


This library exports function mySum returning sum of its arguments:

... ... ...

... + ... + ... = ...

{ a = input({ type: "number", label: "a", value: 1 }) }
{ b = input({ type: "number", label: "b", value: 2 }) }
{ c = input({ type: "number", label: "c", value: 3 }) }

{a} + {b} + {c} = { mySum3(a, b, c) }

Most importantly, the readme is executing the very code it is sharing repository with, not the latest or whatever version published to npm. This turns readme into a function of its code, thus keeping at least the executed code part ever up-to-date.

Please try it for yourself, join our Discord, or drop me a line at if you're interested in this kind of readme for your project or library!