Use JavaScript to render charts, inputs, and other dynamic, interactive, and graphical content on the client. JavaScript in Markdown can be expressed either as fenced code blocks or inline expressions. You can also import JavaScript modules to share code across pages.
JavaScript runs on load, and re-runs
reactivelywhen variables change.
Fenced code blocksJavaScript fenced code blocks (```js
) are typically used to display content such as charts and inputs. They can also be used to declare top-level variables, say to load data or declare helper functions.
JavaScript blocks come in two forms: expression blocks and program blocks. An expression block looks like this (and note the lack of semicolon):
```js
1 + 2
```
Expression blocks implicitly display, producing:
A program block looks like this (note the semicolon):
const foo = 1 + 2;
A program block doesnât display anything by default, but you can call display
to display something.
JavaScript blocks do not show their code by default. If you want to show the code, use the echo
directive:
```js echo
1 + 2
```
The code is rendered below the output, like so:
1 + 2
Alternatively, if you just want to show the code without running it, set the run
directive to false
:
```js run=false
1 + 2
```
If an expression evaluates to a DOM node, the node is inserted into the page directly above the code block. Use this to create dynamic content such as charts and tables.
document.createTextNode("[insert chart here]")
You can use the DOM API to create content as above, but typically youâll use a helper library such as Hypertext Literal, Observable Plot, or D3 to create content. For example, hereâs a component that displays a greeting:
function greeting(name) {
return html`Hello, <i>${name}</i>!`;
}
greeting("world")
And hereâs a line chart of Appleâs stock price using Observable Plot:
Plot.lineY(aapl, {x: "Date", y: "Close"}).plot({y: {grid: true}})
Code blocks automatically re-run when referenced reactive variables change, or when you edit the page during preview. The block below references the built-in variable now
representing the current time in milliseconds; because now
is reactive, this block runs sixty times a second and each each new span it returns replaces the one previously displayed.
html`<span style=${{color: `hsl(${(now / 10) % 360} 100% 50%)`}}>Rainbow text!</span>`
Inline expressions
JavaScript inline expressions ${â¦}
interpolate values into Markdown. They are typically used to display numbers such as metrics, or to arrange visual elements such as charts into rich HTML layouts.
For example, this paragraph simulates rolling a 20-sided dice:
You rolled ${Math.floor(Math.random() * 20) + 1}.
You rolled . (Reload the page to re-roll.)
Like fenced code blocks, inline expressions automatically re-run when referenced reactive variables change or when you edit the page during preview.
The current time is .
The current time is ${new Date(now).toLocaleTimeString("en-US")}.
Likewise, if an inline expression evaluates to a DOM element or node, it will be inserted into the page. For example, you canâ¦
interpolate a sparkline
interpolate a sparkline ${Plot.plot({axis: null, margin: 0, width: 80, height: 17, x: {type: "band", round: false}, marks: [Plot.rectY(aapl.slice(-15 - number, -1 - number), {x: "Date", y1: 150, y2: "Close", fill: "var(--theme-foreground-focus)"})]})}
or even a reactive input
or even a reactive input ${Inputs.bind(html`<input type=range style="width: 120px;">`, numberInput)} ${number}
into prose.
const numberInput = Inputs.input(0);
const number = Generators.input(numberInput);
Expressions cannot declare top-level reactive variables. To declare a variable, use a code block instead. You can declare a variable in a code block (without displaying it) and then display it somewhere else using an inline expression.
TypeScriptTypeScript fenced code blocks (```ts
) allow TypeScript to be used in place of JavaScript. You can also import TypeScript modules (.ts
). Use the .js
file extension when importing TypeScript modules; TypeScript is transpiled to JavaScript during build.
Framework does not perform type checking during preview or build. If you want the additional safety of type checks, considering using tsc
.
TypeScript fenced code blocks do not currently support implicit display, and TypeScript is not currently allowed in inline expressions.
Explicit displayThe built-in display
function displays the specified value.
const x = Math.random();
display(x);
You can display structured objects, too. Click on the object below to inspect it.
display({hello: {subject: "world"}, numbers: [1, 2, 3, 4]})
Calling display
multiple times will display multiple values. Values are displayed in the order they are received. Previously-displayed values will be cleared when the associated code block or inline expression is invalidated.
for (let i = 0; i < 5; ++i) {
display(i);
}
If you pass display
a DOM node, it will be inserted directly into the page. Use this technique to render dynamic displays of data, such as charts and tables.
display(html`Your lucky number is ${Math.floor(Math.random () * 10)}!`);
This is a contrived example â you normally use an inline expression to interpolate a value into Markdown. For example:
Your lucky number is ${Math.floor(Math.random () * 10)}!
The display
function returns the passed-in value. You can display any value (any expression) in code, not only top-level variables; use this as an alternative to console.log
to debug your code.
const y = display(Math.random());
The value of y
is .
The value of `y` is ${y}.
When the value passed to display
is not a DOM element or node, the behavior of display
depends on whether it is called within a fenced code block or an inline expression. In fenced code blocks, display
will use the inspector.
display([1, 2, 3]);
In inline expressions, display
will coerce non-DOM values to strings and concatenate iterables.
${display([1, 2, 3])}
The display
function is scoped to each code block, meaning that the display
function is a closure bound to where it will display on the page. But you can capture a code blockâs display
function by assigning it to a top-level variable:
const displayThere = display;
Then you can reference it from other cells:
Inputs.button("Click me", {value: 0, reduce: (i) => displayThere(++i)})
Implicit display
JavaScript expression fenced code blocks are implicitly wrapped with a call to display
. For example, this arithmetic expression displays implicitly:
1 + 2
Implicit display only applies to expression code blocks, not program code blocks: the value wonât implicitly display if you add a semicolon. (Watch out for Prettier!)
1 + 2;
Implicit display also doesnât apply if you reference the display
function explicitly (i.e., we wouldnât want to show 2
twice below).
display(1), display(2)
The same is true for inline expressions ${â¦}
.
${1 + 2}
${display(1), display(2)}
Implicit display also implicitly awaits promises.
Responsive displayIn Markdown, the built-in width
reactive variable represents the current width of the main element. This variable is implemented by Generators.width
and backed by a ResizeObserver
. The reactive width can be a handy thing to pass, say, as the width option to Observable Plot.
Plot.barX([9, 4, 8, 1, 11, 3, 4, 2, 7, 5]).plot({width})
For non-top-level elements, as when rendering content within an inline expression, use the built-in resize
function instead. This takes a render function which is called whenever the width or height changes, and the element returned by the render function is inserted into the DOM.
<div class="card">
${resize((width) => Plot.barX([9, 4, 8, 1, 11, 3, 4, 2, 7, 5]).plot({width}))}
</div>
If your container defines a height, such as 240px
in the example below, then you can use both the width
and height
arguments to the render function:
<div class="grid grid-cols-2" style="grid-auto-rows: 240px;">
<div class="card" style="padding: 0;">
${resize((width, height) => Plot.barY([9, 4, 8, 1, 11, 3, 4, 2, 7, 5]).plot({width, height}))}
</div>
<div class="card" style="padding: 0;">
${resize((width, height) => Plot.barY([3, 4, 2, 7, 5, 9, 4, 8, 1, 11]).plot({width, height}))}
</div>
</div>
If you are using resize
with both width
and height
and see nothing rendered, it may be because your parent container does not have its own height specified. When both arguments are used, the rendered element is implicitly position: absolute
to avoid affecting the size of its parent and causing a feedback loop.
Displays the specified value in the current context, returning value. If value is a DOM element or node, it is inserted directly into the page. Otherwise, if the current context is a fenced code block, inspects the specified value; or, if the current context is an inline expression, coerces the specified value to a string and displays it as text.
display(1 + 2);
See Explicit display for more.
resize(render)Creates and returns a DIV element to contain responsive content; then, using a ResizeObserver
to observe changes to the returned elementâs size, calls the specified render function with the new width and height whenever the size changes. The element returned by the render function is inserted into the DIV element, replacing any previously-rendered content. This is useful for responsive charts.
resize((width) => `I am ${width} pixels wide.`)
If the render function returns a promise, the promise is implicitly awaited. If the resulting value is null, the DIV element is cleared; otherwise, if the resulting value is not a DOM element, it is coerced to a string and displayed as text.
See Responsive display for more.
widthThe current width of the main element in pixels as a reactive variable. A fenced code block or inline expression that references width
will re-run whenever the width of the main element changes, such as when the window is resized; often used for responsive charts.
width
See Generators.width
for implementation.
The current time in milliseconds since Unix epoch as a reactive variable. A fenced code block or inline expression that references now
will run continuously; often used for simple animations.
now
See Generators.now
for implementation.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4