Custom elements¶
Add a component to your slides with a custom element.
A custom element is a web standard, so it needs no framework and no compiler. You write one .js file and one small stylesheet, and then you list them in deck.yml:
extra_css: [theme/marks.css]
extra_js: [theme/marks.js]
Markdown passes HTML through, so you use the element in the text of a slide:
Departure speed reaches <deck-mark type="circle">2.10 m/s</deck-mark> at 22 N m.
Example: hand-drawn marks¶
This component circles a number on the slide. It uses rough-notation, a 10 KB library that draws sketched marks over any element. The script imports it from a CDN, so the slide needs a network connection.
// theme/marks.js
(async () => {
const { annotate } = await import("https://esm.sh/rough-notation@0.5.1");
class DeckMark extends HTMLElement {
connectedCallback() {
if (this.annotation) { return; } // reveal moves the node, so guard it
this.annotation = annotate(this, {
type: this.getAttribute("type") || "circle", // circle, underline, box, highlight
color: this.getAttribute("color") || "var(--mkd-accent)",
strokeWidth: 2,
padding: 6,
animationDuration: 700,
multiline: this.hasAttribute("multiline"),
});
// Draw the mark when the slide arrives. Reset it when the slide leaves,
// so a second visit draws it again.
this.unsubscribe = window.mkdeck.onSlide(({ slide }) => {
if (slide && slide.contains(this)) { this.annotation.show(); }
else { this.annotation.hide(); }
});
}
disconnectedCallback() {
if (this.unsubscribe) { this.unsubscribe(); }
}
}
customElements.define("deck-mark", DeckMark);
})();
The script defines the element once the import arrives. A <deck-mark> already on the page upgrades at that moment, so the order does not matter.
The element is inline, so it must not move the line. Add this rule to theme/marks.css:
deck-mark { display: inline; position: relative; }
Draw on your own cue¶
To draw the mark while you speak, use a reveal.js fragment. A fragment advances on the next key press:
Departure speed reaches
<deck-mark class="fragment" type="circle">2.10 m/s</deck-mark> at 22 N m.
Then replace the onSlide call in connectedCallback with these lines. They listen for the two events that reveal.js fires on the fragment:
this.addEventListener("visible", () => this.annotation.show());
this.addEventListener("hidden", () => this.annotation.hide());
The number stays on the slide. The circle appears when you press space.
Next: Vendored libraries.