Using Drafts Templates

Template Basics

Drafts actions consist of “steps.” Action steps are available for a wide range of functions and services: Sending messages, mail, saving files, and much more. Regardless of the purpose of the step, any step that output information has some fields that allow you to control what text the step uses, and (with a few minor exceptions) use templates to dynamically generate that text.

If you have poked around in the action editor and wondered what some of those [[title]] and [[body]] things are, this article is for you.

Templates are plain text combined with tags. Consider tags placeholders for some piece of information you want to be inserted when the action is run. Drafts tags are identified by double square brackets ([[ ]]), surrounding the tag name and options. Most tags insert some content or meta data related to the current draft on which an action is being performed.

About Mustache Templates…

Drafts also supports more advanced Mustache templates as an option if you have templating needs like conditional blocks, iterating over items, etc. Those are not covered in this article, see User Guide for more information.

Common Content Tags

The tags that get the most use, and which you are likely to see as defaults in many action steps, are:

  • [[draft]] : Replaced with full text of the current draft.
  • [[title]] : Replaced with text of the first line of a draft.
  • [[body]] : Replace with everything but the first line of the draft.

Take the “Copy” action, which ships with Drafts in the “Basic” action group. The action places the contents of the current draft in the clipboard. The action itself consists of one Clipboard action step, with the template [[draft]]. If you wanted an action that copied just the first line of the draft to the clipboard, you could change the template of the clipboard action step to [[title]].

The default “Mail” action, which ships with the app, uses the [[title]] tag for the subject line of the email, and [[body]] as the content of the email.

You can mix tags with static text in templates, so you could also have the template string Title: [[title]], which would produce the first line of the draft, with the prefix Title: .

There is a handy [[line|n]] tag that lets you extract individual or ranges of lines from the content of a draft. The line tag is an example of a tag with a formatting option, separated from the tag name by a | pipe character. In this case, that option takes line number (1 for the first, 2 for the second, etc.), or range, like 1..3 for first through the third line. If you omit the beginning or end line number, the range will assume beginning or end, so ..4 is the first four lines, and 5.. is the fifth line to the end of the draft. Negative indexes which count back from the end can also be used, so [[line|-1]] would get you just the last line.

The linke can be very useful in splitting up values from a draft into separate values. Say you want an action that saves to a folder in Dropbox, but you want to specify that in the draft itself. You could type the following draft:

My File Name
Personal

The content of the draft.

Then have an action configured with a Dropbox action step using the following template values for its fields:

  • Name: [[line|1]].txt
  • Path: /[[line|2]]/
  • Template: [[line|3..]]

Using this action, on the draft sample text above would result in a file on Dropbox named “My File Name.txt” in the folder “Personal”, with the content “The content of the draft.”

Date and Time Tags

Another commonly used set of tags are date-related tags. The available date tags are:

  • [[date]]: Current date, defaulting to the format %Y-%m-%d, which is equivalent to YYYY-MM-DD.
  • [[created]]: The date the current draft was created.
  • [[modified]]: The date the content of the current draft was last modified.

Each of these tags can also take a formatting string, after the | separator, using strftime formatting. There are formatting characters to allow configuration of almost any possible date and time string - including year, month names, day names, and much more. The Apple strftime reference has details on all the available options. A few commonly used format examples:

  • [[date|%Y-%m-%d]] : Result: 2019-01-31
  • [[date|%I:%M %p]] : Result: 06:19 PM
  • [[date|%d %B %Y %H:%M:%S]] : Result: 31 January 2019 21:19:20

To test strftime formats, we also recommend strftime.net, an online format builder which previews the output of format strings.

The most common use case for date tags is timestamping when appending to a daily journal file, or starting a draft from a template.

Date tags also support more advanced and localizable strings using Apple’s DateFormatter. If you need more advanced date options, take a look at the complete date formatting docs in the User Guide.

Adjust Date Tags

Ever want to insert a date relative to now? Like tomorrow’s date? A week from today? In addition to the format parameter described above, date tags can also accept an optional “adjustment expression” that allows you to add or subtract time and generate a relative date. These expressions are in the format (+/-)(n) (unit), where a + or - indicates if you are adding or subtracting, the n is an integer number and unit is a time unit. Supported units are year, month, day, hour, minute, and second. Units can be singular or plural.

Expressions can have more than one block, so +1 year +2 days would add both a year and 2 days to the date. A few examples:

  • [[date|+1 day|%Y-%m-%d]] : Result when run on Jan. 30, 2022: 2022-01-31
  • [[date|+1 hour +30 minutes|%I:%M %p]] : Result when run at 6:00 PM: 07:30 PM

Install the “Insert Tomorrow” example action to see date adjustment in action.

More information on adjusting dates is available in the User Guide.

Additional Tags

Visit the template tag reference for a complete list of available built-in tags. Using tags you can access information like location data stored with a draft, its UUID and permalink, tags, and more.

No Tags Required

Keep in mind that just because templates in actions can contain tags to dynamically insert text, they don’t need to. Many times you just want plain static text in a template to add boilerplate snippets,

Special Template Markup

In addition to tags, there are a couple of special markup conventions used in templates for convenience, they are:

  • {{ }} : Any text between double curly braces will be URL encoded for use in URL query parameters. This is typically used in Open URL action steps to properly encode text to be included in a URL.
  • %% %% : Any text between double percent signs will be converted from Markdown to HTML using your default Markdown options. Useful when publishing to locations that want HTML input.
  • <<textexpander-shortcut>> [iOS Only] : If you use TextExpander, it is possible to dynamically expand a TextExpander snippet when a template is evaluated. Generally useful for snippets you do not want to be expanded until the action is run because they contain dates or other output which is time-sensitive. To expand a snippet in a template, wrap the snippet’s shortcut text in << >>.

Conclusion

With just a few tweaks to templates, you can create an array of useful actions that save time and formatting.

19 Likes

Re: Textexpander
Is there something I am doing wrong? or some setting I missed? Attempting to enclose the TE shortcut doesn’t seem to work. <<TE-Shortcut>> The last bracket doesn’t appear to be a part of the code. It does not expand.

2 Likes

A few troubleshooting questions:

  • You have a snippet with the shortcut “TE-Shortcut”?
  • It’s an exact match (e.g. case-sensitive)?
  • Your snippets are refreshed, and TE expansion and “expand in actions” are enabled in Drafts settings?
  • You can type that snippet in a draft and it works?
  • It’s not a fill-in snippet? Those cannot be dynamically evaluated, only as you type.

That was an example only.
The snippet is actually ddate. It inserts the current date at the location.
Yes. It is an exact match.
All is refreshed and enabled.
Yes it works in drafts and every where else too.
This is what it looks like in the document

2 Likes

How are you applying the snippet for expansion? Is it simply an Insert Text action or are you using another method to initiate the evaluation?

Yikes! It was an operator error! Problem solved!

It was a lack of understanding on my part.

Hello, How to specify the location of the cursor in a template.

If you are using an action as a trigger, you can modify the cursor position using the editor.setSelectedRange() in a script action.

If that isn’t the case, can you please provide full details of what you are doing with the information in the previous posts?

The links in this article are broken, for instance the link to “template reference” under Additional Tags goes to the home page of the user guide rather than the actual reference page, and other links 404. Would be useful if this could be fixed.

1 Like

Updated links, thanks!

2 Likes

Clipboard action step link in the 5th paragraph appears to still be a broken link.

It appears to be pointing to this URL.

1 Like

Not sure if templates are the right way to go about this, but here goes. I’m trying to create a boilerplate for our Instagram posts where our editors can type/fill the following fields, of which most are variable in length.

title
subtitle
body
hashtags

I understand how to do body and hashtags, but I’m not sure how to deal with the variable length for title and subtitle. [[title]] will only select the first line of the draft and I don’t think I can use [[line:2-X]. because X is unknown.

How would I solve this?

All info will be sent to an iOS shortcut for further processing (where I need to process all the different fields again)

It the title actually likely to be more than one line? Note that lines are defined by an invisible line feed (\n) character, and are not affected by the text soft-wrapping to the next line in the display.

Certainly a variety of ways to approach the problem. If you genuinely have values of varying numbers of lines, you likely need to add some delimiter markup to reliable split the text. So your template might be something like:

title
===
subtitle
===
body
===
hashtags

Then in code those values could be split on the delimiter:

// split values on "===" and trim whitespace
let fields = draft.content.split("===").map(n => n.trim());
// now
let title = fields[0];
let subtitle = fields[1];
// etc.
1 Like

I am having trouble getting the new obsidian note to trigger a note template I have in Obsidian. I have a meta template in obsidian so that if I put “New Note (j)” it knows that “(j)” should trigger the journal template.

When I put “Entry 1 (j)” as note name for Obsidian, it’s not triggering my meta template. Is it possible to trigger the meta template?

This videos shows how to create a meta template: Obsidian: Building the Meta-Templater from Scratch - YouTube

It’s just a set of simple if statements.

I’m not familiar with Obsidian, but it would appear this is a plug-in/extension of the app that modifies files when you create them. For that to occur, you would have to create the file in Obsidian, or that code to add the template would never be fired.

Again, this is speculation, I have not dug into the mechanism, but if you are just writing a file into your Obsidian vault from Drafts, there is no way Obsidian could know about it and run that code.

How are you adding to Obsidian? Perhaps, there is a way to use it’s URL schemes to add in a way that would trigger your template system.

This may be more of a question for an Obsidian forum where people would be more familiar with the mechanisms at the Obsidian end.

1 Like

I’m trying to tweak a script for a document which I need to submit every week. I need the document to have the date for the Monday at the start of the week in its heading, regardless of the day I actually create the document on. I can’t work out the strftime for it though - does anyone know what it would be? Thanks!

Template tags can’t exactly help you here. You can adjust a date forward or backward in time in a template tag, but only by static increments. You’ll have to script it.

Drafts includes the flexible date.js library which has helper functions you can use…something like this will get you a date string for last Monday, and create a template tag [[monday]] you can use in action steps after the script in the same action. You’ll likely want to adjust the strftime format string to your needs, but the help above is applicable for that…

let d = Date.today().last().monday()
let dStr = strftime(d, "%Y-%m-%d")
draft.setTemplateTag("monday", dStr)
2 Likes