A Tiny Roam Tweak

We use Roam extensively at work, but as I am prone to do, I was messing with Roam’s styles to try to make them more pleasing to my eye. One thing I couldn’t style were completed todos. I use the similar OSS tool Logseq for my personal notes/journaling/capture and I find their handling of todo display much nicer.

Maybe there’s a way to get to the text from the checked input in this Roam HTML, but I couldn’t figure it out:

<span>
  <span>
    <label class="check-container">
      <input type="checkbox" checked>
      <span class="checkmark"></span>
    </label>
  </span>
  Sanity Gardening
</span>

Instead, I hacked together some javascript that updates checked todos after a new Roam page loads:

let checkmate = () => {
  var markedCheckbox = document.querySelectorAll('input[type="checkbox"]:checked');
  for (var checkbox of markedCheckbox) {
    checkbox.parentNode.parentNode.parentNode.style.textDecoration = "line-through";
    checkbox.parentNode.parentNode.parentNode.style.color = "lightgray";
  }
}
checkmate();
window.addEventListener('popstate', (event) => {
  window.setTimeout(checkmate, 1000)
});

I could probably listen for something else besides ‘popstate’ and avoid the one second wait, but the content isn’t on the page yet if I don’t use the dreaded ‘setTimeout’.

To use it, you can drag this link to your bookmarks, and click it after loading Roam:

Complete Roam Todos

Since Roam never reloads the actual web page, it should work until you reload Roam for whatever reason. I think there is a way to have embedded JavaScript execute in Roam, but I’m pretty sure it would apply to everyone on my team using the same Roam database.

Here’s an updated version that simply polls every 2 seconds and updates todos. I found that the popstate event wasn’t firing often with my Roam usage, and the original didn’t allow for reformatting unchecked todos back to normal:

let checkmate = () => {
  let markedCheckbox = document.querySelectorAll('input[type="checkbox"]:checked');
  for (var checkbox of markedCheckbox) {
    checkbox.parentNode.parentNode.parentNode.style.textDecoration = "line-through";
    checkbox.parentNode.parentNode.parentNode.style.color = "lightgray";
  }
  let unMarkedCheckbox = document.querySelectorAll('input[type="checkbox"]:not(:checked)')
  for (var checkbox of unMarkedCheckbox) {
    checkbox.parentNode.parentNode.parentNode.style.textDecoration = "none";
    checkbox.parentNode.parentNode.parentNode.style.color = "inherit";
  }
}
setInterval(checkmate, 2000);

Bookmarklet:

Complete Roam Todos


Here’s another one to toggle the bullets next to checkboxes in the sidebar only (I keep my todo list open over there).

document.querySelectorAll("#right-sidebar .rm-query-content div.controls.rm-block__controls").forEach(
  function(bullet){
    if (bullet.style.display == 'none') {
      bullet.style.display = 'flex'
    } else {
      bullet.style.display = 'none'
    }
  }
)

Toggle Todo Bullets

The problem with that one is new todos will have bullets regardless, so the toggle becomes problematic (some will toggle on, some off). Here’s one to remove bullets and keep them removed:

let unbullet = () => {
  document.querySelectorAll("#right-sidebar .rm-query-content div.controls.rm-block__controls").forEach(
    function(bullet) {
      bullet.style.display = 'none'
    }
  )
}
unbullet();
window.addEventListener('popstate', (event) => {
  window.setTimeout(unbullet, 1000)
});

Remove Todo Bullets

Previous: New Video from Tom Conlon

Archives | RSS