Intro
Custom JavaScript can transform your Obsidian setup into a productivity powerhouse.
In this guide, we’ll explore how to leverage custom JavaScript functions in Obsidian using the Dataview and Templater plugins. This can enhance your vault’s functionality and enable code reuse, allowing you to automate and customize tasks efficiently based on your needs.
My journey into creating a smart journal
One of the main reasons I wrote this post was to bring more order into my daily and weekly note-taking workflow.
I keep a daily and weekly work journal. The daily journal helps me to keep track of what I’ve done and prepare for the next day. In my weekly journal, I set some weekly goals and have a higher level view on how I’ve spent my week. It also helps me to present my progress to my teammates in our weekly meetings and give a breakdown of planned vs unplanned work. Now I can walk into weekly meetings with confidence — no more or mumbling about what I did last week!
Writing these pages from scratch and manually copying records from daily notes to the weekly notes would be tedious enough to make me quit. I don’t like quitting!
So here is where Obsidian plugins Dataview and Templater come to the rescue.
I’ve created templates for both daily and weekly notes, each template having a dedicated structure and fields for me to fill. But how to aggregate the daily tasks into a weekly report? Dataview allows me to find all my daily notes for the relevant week. I’m using the DataviewJS, since it allows me greater flexibility than an SQL-like syntax. From the daily notes, I extract tasks completed that day, divided by “planned” and “unplanned” tags along with my achievements list.
Great! But that’s almost a screen long of Javascript code! Surely I can extract all the boilerplate code and reusable snippets out!
Well yes, and let me show you how!
Setting up your vault
Storing your code
Create a folder to store your Javascript files.
I call mine Scripts
and place in my vault root folder.
Place your JavaScript files inside the folder that you have created.
Make sure that you properly define module.exports
.
Attention: Custom scripts in Obsidian only support CommonJS modules. If you’re used to ES Modules, you may need to adjust your code accordingly.
A mock example of Javascript code with two functions and an export section:
function say_message(msg) {
return `Message from my script: ${msg}`;
}
function cow_say(msg) {
return `Cow says ${msg}`;
}
module.exports = { say_message, cow_say };
Notice the required module.exports
to comply with Common.js
syntax.
Configuring the Templater plugin
Under Settings
> Community Plugins
> Templater
> Script files folder location
Set the folder to Scripts
.
When Templater detects user scripts, it displays loaded the scripts as bullets under the header: Detected ${num_of_scripts} User Script(s)
With a list of scripts detected.
Configuring the Dataview plugin
Toggle Enable JavaScript Queries
.
[!Note] Script Folder Configuration Unlike Templater, Dataview doesn’t allow setting up custom script folder in configuration.
Using Custom Scripts
Usage with Templater
An example of code block in an Obsidian page template:
<%*
let title = tp.file.title
if (title.startsWith("Untitled")) {
title = await tp.system.prompt("Title");
await tp.file.rename(title);
}
tp.user.my_script.say_message('Let templater use my custom scripts!')
%>
Notice the following line:
tp.user.my_script.say_message("Let templater use my custom scripts!");
tp.user
- A header to indicate custom scriptsmy_script
- The filename of Javascript file, as stored in the scripts folder.say_message
- The function that you want to call.
Usage with Dataview
There are 3 ways loading the custom scripts in Dataview scripts:
Using scripts as they were loaded at the Obsidian startup
The most common use case.
// Get reference to the script
const myScript = require(dv.app.vault.adapter.basePath +
"/Scripts/my_script.js");
// Use functions exported by the script
dv.paragraph(1, myScript.cow_say("Loading script at Obsidian startup!"));
Reloading the script every time
If you want to reload the referenced library every time without restarting Obsidian. This is very useful for debugging your code.
// Get reference to the script path
const src = dv.app.vault.adapter.basePath + "/Scripts/my_script.js";
// Delete from cache
delete global.require.cache[global.require.resolve(src)];
// Load new version
const myScript = require(src);
// Use functions exported by the script
dv.paragraph(1, myScript.cow_say("Reloading script at Obsidian!"));
Reloading the script asynchronously
This allows you loading your scripts only when needed.
// Execute under some conditions, like file tags.
if (dv.current().file.tags.includes("cows_talk")) {
// Load script
const myScript = await dv.require("/Scripts/my_script.js");
// Use functions exported by the script
dv.paragraph(
1,
myScript.cow_say("Reloading script at Obsidian asynchronously!")
);
}
Summary and final thoughts
In this article I’ve shown how to organize your Javascript code to allow writing smart templates and data views while creating clear, readable and reusable code in Obsidian plugins.
Try implementing your first custom script today, and tag me on social media to share how it enhances your workflow!
Sources: