Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reference the same footnote more than once on a single slide?

I’m creating a Reveal.js presentation using Quarto and I want to cite the same footnote multiple times in the same slide. Here’s a minimal example (all in one .qmd file):

---
title: "test"
format: revealjs
---

## test_1

-   test_1[^1]

-   test_1[^1]

[^1]: test_1 footnote

I get this:

enter image description here

But I want to have like this:

enter image description here

like image 377
TarJae Avatar asked Oct 16 '25 13:10

TarJae


1 Answers

This can be done using JavaScript. First, check all '.aside-footnotes li' list elements for dupes. If any dupe is found, it's hidden and the information of which element it is a dupe is stored. In a second pass, go over all sup elements to replace duplicated footnotes with dupe_of. A third pass checks if the newly created reused footnotes are in order:

out

We are treating each section seperately. It turns out, that the contents are static, but simply the class changes on scroll.

sec

Edit: I introduced some logic to make this work for each slide independently. Now the JS looks at each slide of class .slide.level2 and finds reused footnotes only within the scope of one slide.

Note: This is highly customized and may create unforeseen issues. But this will give you an idea, of how it can be done.

---
title: "test"
format: revealjs
header-includes:
  - |
    <script>
      document.addEventListener('DOMContentLoaded', function() {
      const sections = document.querySelectorAll('.slide.level2'); 
      
      sections.forEach(section => {
          const footnotes = section.querySelectorAll('.aside-footnotes li');
          if (footnotes.length === 0) return;
          
          /*
          console.log('Processing section:', section);
          console.log('Footnotes:', Array.from(footnotes).map(f => ({
              id: f.id,
              text: f.querySelector('p').textContent.trim()
          })));
          */
          const contentToNumber = new Map();
          let currentUniqueNumber = 1;
          
          const firstFootnoteNumber = parseInt(footnotes[0].id.match(/\d+/)[0]);
          console.log('First footnote number in section:', firstFootnoteNumber);
          
          // to correct number mapping-
          footnotes.forEach((footnote) => {
              const footnoteText = footnote.querySelector('p').textContent.trim();
              if (!contentToNumber.has(footnoteText)) {
                  contentToNumber.set(footnoteText, currentUniqueNumber);
                  currentUniqueNumber++;
              }
          });
          
          // Create sequential to unique number mapping
          const numberMapping = new Map();
          footnotes.forEach((footnote, index) => {
              const footnoteText = footnote.querySelector('p').textContent.trim();
              const absoluteNumber = parseInt(footnote.id.match(/\d+/)[0]);
              const sequentialNumber = absoluteNumber - firstFootnoteNumber + 1;
              const correctNumber = contentToNumber.get(footnoteText);
              
              // Map sequential numbers, since footnotes count upwards accross slides :(
              numberMapping.set(sequentialNumber, correctNumber);
              
              console.log(`Mapping sequential ${sequentialNumber} (absolute ${absoluteNumber}) to ${correctNumber}`);
              
              if (index > 0 && Array.from(footnotes)
                  .slice(0, index)
                  .some(f => f.querySelector('p').textContent.trim() === footnoteText)) {
                  footnote.style.display = 'none';
              }
          });
          
          // Update sup elements
          const supElements = section.querySelectorAll('sup');
          supElements.forEach(sup => {
              const currentNumber = parseInt(sup.textContent.trim());
              const correctNumber = numberMapping.get(currentNumber);
              
              console.log(`Sup element: ${currentNumber} -> ${correctNumber}`);
              
              if (correctNumber !== undefined) {
                  sup.textContent = correctNumber.toString();
              } else {
                  console.log(`Warning: No mapping found for sup number ${currentNumber}`);
              }
          });
      });
      });
    </script>
---
## Footnotes

-  Apple [^1]
-  Banana [^1]
-  Raspberry [^1]
-  Tomato [^2]
-  Potato [^2]


[^1]: Fruit
[^2]: Veggie

## Going to sleep

- Get in bed [^3]
- or even a tent [^3]

[^3]: form of shelter

## combination and repetition  
-  Apple [^1] 
-  Banana [^1] 
-  Raspberry [^1] 
-  Tomato [^2] 
-  Potato [^2] 
- Get in bed [^3] 
- or even a tent [^3]  

[^1]: Fruit 
[^2]: Veggie 
[^3]: form of shelter
like image 83
Tim G Avatar answered Oct 19 '25 13:10

Tim G



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!