Dynamic Forms for NotePlan using Templating -- fill out a multi-field form and have the data sent to a template for processing
See CHANGELOG for latest updates/changes to this plugin.
The Forms plugin enables you to create dynamic, interactive forms in NotePlan for things you do frequently -- e.g. create meeting note, contact notes, etc. You define form fields using the visual Form Builder, and when you fill out the form and click "Submit", the data is automatically processed to create notes or write to existing notes - no coding or template writing required!
⚠️ Beta Warning: This is an early beta release and may not yet be fully functional. Features may change, and you may encounter bugs or incomplete functionality. Please report issues to @dwertheimer on Discord.
Build the form once in the Form Builder:
![]()
Then use the form every day to create new notes with whatever information you want:
![]()
/builder in the command bar/form and select your form, fill it out, and submit!That's it! No templates to write, no JSON to edit, no advanced configuration needed for typical use cases.
The Form Builder is where you'll do everything. It's a visual interface that lets you:
Type any of these commands:
/builder/buildform/📝 Forms: Form Builder/EditorLaunch Form Builder: Type /builder
Create New Form: Click "Create New Form" and give it a name (e.g., "Project Form")
Add Fields: Click "+ Add Field" and select field types:
Configure Each Field: Click on a field to edit:
Configure Form Output (left sidebar under "Form Settings"):
Option 1: Create New Note (most common)
<%- projectName %>)Option 2: Write to Existing Note
<today> for today's note, or a specific note title)Save Your Form: Click "Save Form" button
Test Your Form: Click "Open Form" to test it right away
The Form Builder lets you configure exactly what happens when the form is submitted:
Perfect for: Project notes, meeting notes, person notes, etc.
Configuration:
<%- projectName %><select> to choose each time)# <%- projectName %>
**Start Date:** <%- startDate %>
**Team:** <%- team %>
## Description
<%- description %>
Perfect for: Adding to today's note, logging entries, appending to project notes, etc.
Configuration:
<today> - Today's daily note<current> - Currently open note<choose> - Prompt to choose note each timeMethod 1: Command Bar (easiest)
/form or /dialogMethod 2: x-callback URL Link
When you create a form, a launch link is automatically added to the top of your form template. Copy that link and paste it anywhere (daily notes, project notes, etc.) to launch the form with one click.
Example: [Launch My Form](noteplan://x-callback-url/runPlugin?pluginID=dwertheimer.Forms&command=Open%20Template%20Form&arg0=My%20Form)
Method 3: Auto-Open on Note Open (advanced)
Forms can auto-open when you open certain notes by adding this to the note's frontmatter:
triggers: onOpen => dwertheimer.Forms.triggerOpenForm
View all your forms in a browsable interface:
Type /browser or /formbrowser
The Form Browser shows all your forms in a two-column layout where you can:
The Form Builder includes these field types:
Forms automatically save your progress. If a form is closed before submitting, you can restore it:
Type /restoreautosave or /restoreform
Autosave files are stored in @Trash/Autosave-{timestamp} by default.
Browse all your forms in a visual interface:
Type /browser or /formbrowser
Can open as a floating window: /formbrowser true
The Forms plugin has one main setting:
Enable Autosave for All Forms (default: ON)
You can disable this globally and add autosave to specific forms only if preferred.
dependsOnKey)type: template-form in frontmatter/restoreautosave commandMost users won't need anything below this line. The sections below are for advanced users who need custom processing logic or want to understand the underlying structure.
When developing or testing forms, you may want to open the saved HTML file in Chrome without being connected to NotePlan. By default, chooser fields (folder-chooser, note-chooser, space-chooser, etc.) load their data dynamically from NotePlan, which requires an active connection.
To enable preloaded data:
Add this to your form's frontmatter:
preloadChooserData: true
When preloadChooserData: true is set, the form will preload all chooser data when the HTML file is created:
The preloaded data is embedded in the saved HTML file (form_output.html), allowing you to:
Note: Preloaded data is a snapshot taken when the HTML is generated. For production use, leave preloadChooserData unset (or false) to use dynamic loading for up-to-date data.
For advanced use cases that can't be handled by the Form Builder's built-in options, you can create custom processing templates.
When you might need this:
Creating a Processing Template:
/createprocessor or /newprocessorProcessing Template Structure:
---
title: My Processing Template
type: forms-processor
newNoteTitle: <%- fieldName %>
folder: /Projects
---
# Template body here
Use form fields like: <%- fieldName %>
All form field key values become variables in your template.
Date Formatting Example:
<%- startDate ? date.format("YYYY-MM-DD", startDate) : '' %>
Conditional Logic Example:
<% if (isUrgent) { %>
**URGENT:** Requires immediate attention
<% } %>
The Form Builder uses these processing methods:
You typically don't need this - use Form Builder instead!
Form templates are stored as NotePlan notes with:
type: template-form in frontmatterformfields code block with JSON array of field definitionsSee the end of this document for complete JSON field reference if you need to edit manually.
For executing custom JavaScript during form processing:
Example:
// Create a folder based on form data
const folderPath = `${parentFolder}/${projectName}`;
DataStore.createFolder(folderPath);
Don't use these as field keys (the plugin uses them internally):
__isJSON__, submit, location, writeUnderHeadingopenNoteTitle, writeNoteTitle, getNoteTitledreplaceNoteContents, createMissingHeadingreceivingTemplateTitle, windowTitle, formTitlewidth, height, hideDependentItems, allowEmptySubmit, titleNote: You typically don't need this - the Form Builder provides a visual interface for all field types. This reference is for users who need to manually edit form JSON or understand field properties in detail.
All fields support these properties:
| Property | Type | Description |
|---|---|---|
key | string | Variable name (required for most types) |
label | string | Field label displayed to user |
type | string | Field type (required) |
description | string | Help text shown below field |
default | any | Default value for the field |
value | any | Initial/current value |
compactDisplay | boolean | Label and field side-by-side |
dependsOnKey | string | Make field conditional on another field |
required | boolean | Field must be filled |
placeholder | string | Placeholder text (for input fields) |
input - Text input field
{
key: 'projectName',
label: 'Project Name',
type: 'input',
required: true,
compactDisplay: true,
validationType: 'email' // optional: 'email', 'number', 'date-interval'
}
textarea - Multi-line expandable text field
{
key: 'description',
label: 'Description',
type: 'textarea',
placeholder: 'Enter description...'
}
number - Numeric input
{
key: 'quantity',
label: 'Quantity',
type: 'number',
default: 1,
step: 1 // increment amount
}
input-readonly - Read-only display field
{
key: 'displayOnly',
label: 'Read-only',
type: 'input-readonly',
value: 'Cannot be changed'
}
dropdown-select - Simple dropdown
{
key: 'team',
label: 'Team',
type: 'dropdown-select',
options: ['Alpha', 'Beta', 'Charlie'],
// or with explicit values:
// options: [{label: 'Alpha', value: 'a'}, {label: 'Beta', value: 'b'}],
default: 'Beta'
}
switch - Toggle on/off
{
key: 'isUrgent',
label: 'Urgent',
type: 'switch',
default: false
}
button-group - Mutually exclusive buttons
{
key: 'priority',
label: 'Priority',
type: 'button-group',
options: [
{label: 'High', value: 'high'},
{label: 'Medium', value: 'med', isDefault: true},
{label: 'Low', value: 'low'}
],
vertical: false // true to stack vertically
}
calendarpicker - Date picker with configurable output format
{
key: 'dueDate',
label: 'Due Date',
type: 'calendarpicker',
buttonText: 'Select Date',
visible: false, // true to show calendar by default
numberOfMonths: 1,
size: 0.75, // scale factor
dateFormat: 'YYYY-MM-DD', // moment.js format string (default: 'YYYY-MM-DD' ISO 8601)
// Use '__object__' to return Date object instead of formatted string
// Examples:
// dateFormat: 'MM/DD/YYYY' - US format (12/25/2024)
// dateFormat: 'DD/MM/YYYY' - European format (25/12/2024)
// dateFormat: 'MMMM Do, YYYY' - Long format (December 25th, 2024)
// dateFormat: 'YYYY-MM-DD HH:mm' - ISO with time (2024-12-25 14:30)
// dateFormat: '__object__' - Returns Date object
}
note-chooser - Searchable note selector (single or multi-select)
{
key: 'targetNote',
label: 'Select Note',
type: 'note-chooser',
placeholder: 'Search notes...',
showValue: false, // false=show title, true=show filename
// Multi-select options:
allowMultiSelect: true, // Enable multi-select mode (default: false)
noteOutputFormat: 'wikilink', // 'wikilink' | 'pretty-link' | 'raw-url' (default: 'wikilink')
noteSeparator: 'space', // 'space' | 'comma' | 'newline' (default: 'space')
// Filter options:
includePersonalNotes: true, // Include personal/project notes (default: true)
includeCalendarNotes: false, // Include calendar notes (default: false)
includeRelativeNotes: false, // Include relative notes like <today> (default: false)
includeTeamspaceNotes: true, // Include teamspace notes (default: true)
includeTemplatesAndForms: false, // Include @Templates and @Forms folders (default: false)
// Display options:
showCalendarChooserIcon: true, // Show calendar picker button (default: true if calendar notes included)
showTitleOnly: false, // Show only title, not path/title (default: false)
shortDescriptionOnLine2: false // Show description on second line (default: false)
}
folder-chooser - Searchable folder selector
{
key: 'targetFolder',
label: 'Select Folder',
type: 'folder-chooser',
placeholder: 'Search folders...',
includeNewFolderOption: true, // Allow creating new folders
staticOptions: [ // Static options that appear at top of list
{ label: 'Select...', value: '<select>' } // TemplateRunner will prompt user each time
]
}
Folder Chooser Options:
includeArchive (boolean) - Include Archive folder in listincludeNewFolderOption (boolean) - Add "New Folder" option to create foldersstartFolder (string) - Limit folders to a specific subfolder (e.g., "/Projects")includeFolderPath (boolean) - Show full folder path, not just folder name (default: true)excludeTeamspaces (boolean) - Exclude teamspace folders from liststaticOptions (array) - Static options to add at top of list. Each option is {label: string, value: string}. Useful for TemplateRunner special values like <select> which prompts the user each time.sourceSpaceKey (string) - Value dependency: key of a space-chooser field to filter folders by spacespace-chooser - Space/Teamspace selector
{
key: 'space',
label: 'Space',
type: 'space-chooser',
placeholder: 'Select space...'
}
heading-chooser - Heading selector (static or dynamic)
{
key: 'heading',
label: 'Select Heading',
type: 'heading-chooser',
noteFilename: 'project.md', // static note
// OR
noteFieldKey: 'targetNote', // get note from another field
placeholder: 'Select heading...'
}
event-chooser - Calendar event selector
{
key: 'meeting',
label: 'Select Event',
type: 'event-chooser',
date: '2024-01-15', // static date
// OR
dateFieldKey: 'eventDate', // get date from another field
placeholder: 'Select event...'
}
tag-chooser - Multi-select hashtags
{
key: 'tags',
label: 'Tags',
type: 'tag-chooser',
returnAsArray: false // false=comma-separated, true=array
}
mention-chooser - Multi-select @mentions
{
key: 'people',
label: 'People',
type: 'mention-chooser',
returnAsArray: false
}
frontmatter-key-chooser - Frontmatter value selector
{
key: 'status',
label: 'Status',
type: 'frontmatter-key-chooser',
frontmatterKey: 'status', // which frontmatter key to search
returnAsArray: false
}
heading - Section heading
{
type: 'heading',
label: 'Section Title',
description: 'Optional subtitle'
}
separator - Horizontal line
{
type: 'separator'
}
text - Display-only text
{
type: 'text',
label: 'Instructions text here',
textType: 'description' // 'title', 'description', or 'separator'
}
markdown-preview - Display markdown
{
type: 'markdown-preview',
content: '# Hello\n\nMarkdown content', // static content
// OR
noteFilename: 'preview.md', // load from note
// OR
noteFieldKey: 'selectedNote', // load from another field
height: 300 // optional fixed height
}
table-of-contents - Clickable form section links
{
type: 'table-of-contents',
label: 'Form Sections'
}
hidden - Hidden field (not displayed)
{
key: 'hiddenData',
type: 'hidden',
value: 'some-value'
}
json - JSON editor
{
key: 'metadata',
label: 'Metadata',
type: 'json',
default: {}
}
button - Clickable button
{
key: 'actionBtn',
type: 'button',
label: 'Click Me',
isDefault: false // true for primary styling
}
autosave - Auto-save form state
{
type: 'autosave',
key: 'formAutosave',
saveLocation: '@Trash/Autosave-<ISO8601>',
autoSaveInterval: 30000, // milliseconds
showStatus: true
}
templatejs-block - JavaScript execution (advanced)
{
type: 'templatejs-block',
key: 'myScript',
label: 'Script',
templateJSContent: 'const result = await doSomething(); return result;',
executeTiming: 'after' // 'before' or 'after'
}
Make fields dependent on other fields:
{
key: 'showAdvanced',
label: 'Show Advanced',
type: 'switch',
default: false
},
{
key: 'advancedOption',
label: 'Advanced Option',
type: 'input',
dependsOnKey: 'showAdvanced' // only enabled when showAdvanced is true
}
---
title: Project Form
type: template-form
processingMethod: create-new
windowTitle: "New Project"
width: 750
height: 600
---
[Run Form: Project Form](noteplan://x-callback-url/runPlugin?pluginID=dwertheimer.Forms&command=Open%20Template%20Form&arg0=Project%20Form)
```formfields
[
{
type: 'heading',
label: 'Project Details'
},
{
key: 'projectName',
label: 'Project Name',
type: 'input',
required: true,
compactDisplay: true
},
{
key: 'startDate',
label: 'Start Date',
type: 'calendarpicker',
buttonText: 'Select Date'
},
{
key: 'team',
label: 'Team',
type: 'dropdown-select',
options: ['Alpha', 'Beta', 'Charlie'],
compactDisplay: true
},
{
type: 'separator'
},
{
key: 'description',
label: 'Description',
type: 'textarea',
placeholder: 'Enter project description...'
}
]
```