🔌 Plugin system

.lit has a flexible Plugin system, primarily to allow the author to create custom Viewers and REPLs but also includes various other types.

Table of Contents

Anatomy of a plugin

.lit plugins are defined using the !plugin directive on a fenced code block.

```js !plugin id=foo type=bar
// implementation 
export const bar = (...args) => {
  return "I'm a plugin"

Initially it is assumed that a plugin is implemented in js but hopefully due to the flexibility this won't remain the case for long.


Generally plugins are scoped only to the .lit document they're defined in, they are evaluated sequentially and duplicates are overwritten.

If you would like to make a plugin available in all documents then you need to move them to a special config page.

Alternatively just make sure your plugin defines a filename and is an output, and then transclude it like so:

Using transcluded `meta` viewer


Plugins can optionally define a type= attribute. For built in types this is not necessary, but can also be used to exclude implementations that might be defined within.

Implemented yet or not?

  • parser:
  • renderer:
  • viewer:
  • transformer:
  • repl:
  • menu:
  • onsave|onload|onselect:
  • theme:
jsonUpdated 98.5w ago
[ 'theme (1): test',
  'viewer (2): meta, lang',
  'onload (2): sw, example-onload',
  'unknown (0): ',
  'repl (1): lang',
  'menu (2): example-menu, example-modal',
  'onselect (1): example-onselect',
  'onsave (1): example-onsave',
  'data (1): mydata',
  'parser (1): example-parser',
  'renderer (2): 1, example-renderer' ]


The viewer type plugin -- which preceded the !plugin directive as !viewer -- allow the author to define how source content of a fenced code block should be viewed when rendered to html based on its lang.

This is useful for example when the source is json html or svg but as it turns out has many more uses see Viewers for details, built-in viewers and useful examples.

export const viewer = ({node, React}) => {
  return "Example viewer plugin used: " + node.data.value
langusageExample viewer plugin used: content 😊


Initially implemented directly but in the process of being ported to plugins by default. REPLs are one of the cornerstones of .lit allowing the reader to Execute code cells.

They take an input source from fenced code blocks and when executed add or replace an attached output.

export const repl = (src, meta, node) => {
  return `Input was ${src.length} characters long.`
content 😊
txtUpdated 110.5w ago
Input was 11 characters long.


Not yet Implemented.

export const parser = (...args) => {
  return (tree) => {
    tree.data = file.data || {}
    tree.data__examplePluginActive = true


export const renderer = (...args) => {
  return (tree,file) => {
    file.data = file.data || {}
    file.data.__examplePluginActive = true

On Lifecycle plugins

  • onload: Executed once on initial load of the document.
  • onselect: Executed on every cell selection, includes deselection, pos is null.
  • onsave: Executed on save (edit) but before filesystem or state is updated.
export const onload  = (...args) => {
  alert("Custom Onload plugin executed", ...args)
export const onselect = (...args) => {
  console.info("Custom onselect plugin executed", ...args)
export const onsave = (...args) => {
  alert("Custom onsave plugin executed", ...args)


Since all plugins are extracted (to the global lit object) during parsing, regardless of implementation status, you can define your own. A good example is exporting data to be used in other cells.

export const data = {
  type: "beer",
  bottles: 99,
jsusage> md
const data = lit.file.data.plugins.data.mydata
return `There are **${data.bottles}** bottles of *${data.type}* on the wall.`
mdUpdated 109w ago

There are 99 bottles of beer on the wall.