Created
December 25, 2025 10:48
-
-
Save l-mb/9aac76bb6dd00a09edca3fff13134058 to your computer and use it in GitHub Desktop.
Export the open/checked off checklist item counts to a file property in Obsidian
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // This adds a counter of completed vs total checklist items in a note as a file | |
| // property whenever you update the note. | |
| // I use this together with the TaskNote plugin's Kanban view to give me a "Trello"-like | |
| // experience of items that are still open/completed at a quick glance. | |
| // Customize as you see fit - it might differ based on which task statuses you | |
| // use with Obsidian, for example, or which property names you want. | |
| // | |
| // Pre-requisites: the QuickAdd and Linter plugins | |
| // | |
| // Alternative: turning this into a proper plugin and/or a more complex bases query? | |
| // | |
| // 1. Save this to updateChecklist.js somewhere in your Vault. | |
| // 2. Using the QuickAdd community plugin, configure a Choice of type "Macro" that | |
| // executes the above as a User Script | |
| // 3. Toggle the flash symbol in QuickAdd so it gets exposed as an Obsidian command | |
| // 4. For the Linter community plugin, go to "Custom" settings, and add the QuickAdd | |
| // command for this as a Custom Command to be run after linting | |
| // 5. Ensure that you've set "Lint on save" or even "Lint on Focused File Change" | |
| // If using "Lint on save", you'll have to explicitly invoke save (ctrl-s). | |
| // 6. When using Obsidian Sync, ensure that you've enabled "Sync all other types" too! | |
| // Otherwise, the .js file won't be sync'ed, and QuickAdd will fail to load on | |
| // other nodes. | |
| module.exports = async (params) => { | |
| const { app, obsidian } = params; | |
| const activeFile = app.workspace.getActiveFile(); | |
| if (!activeFile) { | |
| new obsidian.Notice("No active file"); | |
| return; | |
| } | |
| const content = await app.vault.read(activeFile); | |
| const uncheckedRegex = /^[\s]*- \[[ \/\<PD]\]/gm; | |
| const checkedRegex = /^[\s]*- \[[xXM\>]\]/gm; | |
| const uncheckedMatches = content.match(uncheckedRegex) || []; | |
| const checkedMatches = content.match(checkedRegex) || []; | |
| const done = checkedMatches.length; | |
| const total = uncheckedMatches.length + done; | |
| await app.fileManager.processFrontMatter(activeFile, (frontmatter) => { | |
| if (total > 0) { | |
| // If you want to expose them as individual numbers, uncomment this: | |
| // frontmatter.tasks_total = total; | |
| // frontmatter.tasks_done = done; | |
| frontmatter.tasks_progress = total > 0 ? `${done}/${total}` : "0/0"; | |
| } else { | |
| // If there are no tasks left, remove the attributes: | |
| delete frontmatter.tasks_total; | |
| delete frontmatter.tasks_done; | |
| delete frontmatter.tasks_progress; | |
| } | |
| }); | |
| }; |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
An example how this view could look like with TaskNotes