Examples
A button you can ride.
The button below is rendered by the extension as this page is built. Scroll down first, then press it.
Giving it a label and a target
The first argument is the label, the second the id of the element to stop at.
{{< elevator "Back to the header" my-header >}}A target is written without its leading #, and needs a label in front of it, since the second argument is only read when the first is present.
What the label may contain
The label reaches the button as plain text. A quoted argument is passed through as it was typed, so markdown inside it is not read and HTML inside it is escaped.
{{< elevator "**Go** up" >}}That call renders:
<button class="btn btn-outline-primary elevator-button" type="submit">**Go** up</button>The asterisks are part of the label.
{{< elevator "<b>Go</b> up & down" >}}That one renders:
<button class="btn btn-outline-primary elevator-button" type="submit"><b>Go</b> up & down</button>The tags are shown rather than applied, and the ampersand is escaped. Neither call is rendered live here, because a page carries one working button and this page already has one.
The label is also the accessible name of the button, which is the text a screen reader announces. Write a label that says where the button goes, and leave the formatting out of it.
Pointing at a heading
A target is an id that already exists on the page. Give the heading an id, then name that id without its #:
## The controls {#the-controls}
Some text.
{{< elevator "Back to the controls" the-controls >}}Write the target after a label, never on its own. A single argument is always read as the label, so the call below produces a button reading the-controls, which still rides to the top of the page:
{{< elevator the-controls >}}An id that no element carries is not an error. The ride falls back to the top of the page.
Adding music
audio plays for the length of the ride, and end names the sound played on arrival.
{{< elevator "Going up" audio=music.mp3 end=arrived.mp3 >}}Each one takes a path relative to your document. The name ding is built in, and both attributes accept it. It resolves to the sound shipped with the extension, which is also the sound end plays when you leave it out. See Getting the sounds into the output for where the files have to be.
volume applies to both sounds, and is worth setting well below 1.0:
{{< elevator audio=music.mp3 volume=0.4 >}}By default the music loops until the ride finishes. Turn that off to play it once:
{{< elevator audio=music.mp3 loop-audio=false >}}Volume without music
volume reaches every sound the elevator builds, and the arrival sound is one of them. It is worth setting even where there is no ride music:
{{< elevator volume=0.2 >}}That button plays the bundled arrival sound at a fifth of its volume.
What loop-audio needs
loop-audio acts on the ride music alone. Elevator.js sets the loop on the main audio, and only where audio is given. Written on its own, the option reaches the page and has nothing to act on:
{{< elevator loop-audio=false >}}That button sounds exactly like the default one. Pair the option with audio for it to mean anything:
{{< elevator audio=music.mp3 loop-audio=false >}}The arrival sound never loops, whatever loop-audio says. Write the value as true or false.
Getting the sounds into the output
A sound plays only where the browser can fetch it.
Render one document on its own, and Quarto writes the page beside the source. A sound file beside that source is then already in place.
A project that writes to an output directory needs more. The audio path appears only inside the script the shortcode writes, and Quarto does not read that script, so nothing copies the file for you. List the file as a project resource:
project:
type: website
resources:
- music.mp3The bundled arrival sound needs the same care. The shortcode registers it while the page renders, which is after Quarto has resolved the project resources, so it lands in the project directory rather than in the output directory. This site copies it in before the render and lists it under resources, which is why the button at the top of this page dings.
A file the browser cannot fetch produces no warning at render time. The sound whose file is missing does not play, and the others still do. A missing audio leaves the ride silent and still sounds the arrival, because the arrival sound is fetched on its own, whether it is the bundled one or a file end names.
Calling it from the keyboard
shortcut binds one key, matched against the browser’s KeyboardEvent.key:
{{< elevator audio=music.mp3 shortcut="t" >}}The key is ignored while the focus sits in a form field or any editable element, so it will not fire while a reader is typing in the search box.
Keyboard and screen readers
The shortcode writes a real button element. It takes focus in the tab order, and Enter or Space presses it, so the ride on this page works from the keyboard. Its accessible name comes from the label, and the extension adds no aria-label that could override it.
Quarto’s back-to-top pill is not the same. Quarto writes it as a link with no address and with role="button", so it announces itself as a button and never takes focus. The extension replaces what a click on the pill does, and adds nothing that puts the pill in the tab order. Keep the button from the shortcode on the page for readers who do not use a mouse.
Nothing moves the focus after the ride. The page scrolls, and the next Tab carries on from the button, not from the top of the page and not from the target.
The ride is always animated. Neither the extension nor Elevator.js reads prefers-reduced-motion.
shortcut binds one key across the whole page, and the handler cancels the usual action of that key everywhere outside form fields and editable elements. Choose a key that the browser and the reader’s assistive software do not already use.
Where Quarto’s back-to-top pill is on the page, shortcut is bound once for each control. One press then starts two rides at once and plays the sounds twice.
Turning it off
Set the option in the document front matter, or in _quarto.yml for a whole project:
extensions:
elevator:
enabled: falseEvery elevator shortcode then renders nothing, which is a quicker way to silence a site than removing the shortcodes one by one.
Source
The repository ships a short, standalone starting point you can copy: example.qmd.