Interactive task-list checkboxes in the Markdown preview — now that the MultiMarkdown dependency is gone

Long-time user, first substantial feature request. I know this has come up before (this category’s “Feature Request: Markdown checkboxes” from 2017, “Feature request: Checkboxes in Markdown” from 2019, and “Clickable Markdown checkboxes in the preview” from 2022) — I’m re-raising it deliberately, because I believe DEVONthink 4.3 removed the main historical objection.

The request: In the rendered Markdown preview, let a click on a GFM task-list checkbox (-  / -  ) toggle it — and write that toggle back to the source line.

Why re-raise it now: The consistent answer over the years was “we use MultiMarkdown, request GFM features there.” Fair enough at the time. But DEVONthink 4.3’s release notes describe a new in-house parser that already combines MultiMarkdown, CommonMark and GitHub-flavored features — and it renders task-list checkboxes today. The parser dependency argument no longer applies; what’s missing is only the write-back on click.

On the “no way back from HTML to Markdown” objection (raised by community members in the 2022 thread): true in general, but task-list items are the special case where it is well-defined. Each rendered <li> of a task list maps 1:1 to exactly one source line, and the only mutation needed is [ ][x] in that line — a three-character, line-addressable edit. No general HTML→Markdown round-trip required. Obsidian, GitHub, and Typora all implement exactly this narrow write-back.

My use case (I suspect it generalizes): I run shared checklists — meeting preparations, project run-books — as plain Markdown files in an indexed folder. An assistant process updates them programmatically (plain text is what makes that robust and future-proof — very much the DEVONthink philosophy). DEVONthink is my single place to find, read and archive these files, and with a custom stylesheet they look great in the preview. Everything works — except ticking a box, which today means: switch to source mode, find the line, edit [ ] to [x], switch back. For that one interaction I have to keep a second Markdown app around whose only job is being clickable.

Checking a box is a small feature. But for everyone using DEVONthink as their Markdown hub for checklists and run-books, it’s the difference between “DEVONthink is the one place” and “DEVONthink plus a second app just for clicking.”

(If write-back in the preview is architecturally off the table, even an interim Format ▸ Toggle checkbox command that works from the preview — like the existing behavior in formatted notes — would close most of the gap.)

Thank you for your great work on this amazing tool,

best wishes, Axel

Interactive checkboxes would be nice.

A workaround would be to open the DT document in an external Markdown editor that handles checkboxes. I use iaWriter, although I’m not all that happy with it. It’s great, in the main, but I’ve also gotten intermittent crashes.

I guess “GFM” means “Github flavored markdown”? Not obvious to me, though. If my guess is correct, I’ll quote from the “GFM specs”:

This spec does not define how the checkbox elements are interacted with: in practice, implementors are free to render the checkboxes as disabled or inmutable elements, or they may dynamically handle dynamic interactions (i.e. checking, unchecking) in the final rendered document.

And now as to what DT does:

This markdown

# Heading

- [ ] Task one
- [ ] Task two
- [ ] Task three

gives me this HTML (condensed, leaving out all the non-necessary HTML elements)

<h1 id="heading">Heading</h1>
<ul>
  <li><input type="checkbox" disabled="">Task one</li>
  <li><input type="checkbox" disabled="">Task two</li>
  <li><input type="checkbox" disabled="">Task three</li>
</ul>

That looks standard-conformant to me.

A first step, therefore, would be to render interactable (is that a word?) checkboxes. Which is a fairly trivial task with a little JavaScript script inserted into your MD file(s) like so:

<script>
document.addEventListener('DOMContentLoaded', e => {
  const cb = document.querySelectorAll('input[type="checkbox"]');
  cb.forEach(el => el.disabled = false);
})
</script>

But then… DT probably uses one of Apple’s frameworks to render the HTML. In that case (again: just a guess), how would it even know that someone clicked a checkbox? The only way to be notified of that would be an event listener, written in JavaScript and included with every MD document or the rendered HTML. Feasible, but…this event handler would run in the rendering component’s JavaScript sandbox, not being able to talk back to DT at all. An alternative might be trying the doJavaScript command in DT’s scripting suite, but I couldn’t get that to do anything useful in this context.

I can’t speak for the DT developers, of course, but trying to implement that looks like a lot of work to me. To save a problem in DT that can easily be solved elsewhere, not least by using a ToDo app.

2 Likes