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:
- Open the Form Builder: Type
/builderin the command bar - Create your form: Add fields, configure how you want the data saved (new note or add to existing)
- Use your form: Type
/formand 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.
- You use the Form Builder to visually create a form (no coding required)
- In the Form Builder, you configure how to handle the data:
- Create a new note - Form data creates a new note with the content you specify
- Write to existing note - Form data gets added to an existing note (today's note, a specific note, etc.)
- Run JavaScript - Execute custom JavaScript code (advanced)
- Use custom template - Use a processing template for complex scenarios (advanced)
- When someone fills out the form and clicks "Submit", the plugin automatically handles everything based on your configuration
The Form Builder is where you'll do everything. It's a visual interface that lets you:
- Add form fields by clicking a button (text inputs, dropdowns, date pickers, switches, etc.)
- Configure each field (label, description, default value, required/optional)
- Arrange fields by dragging them
- Configure output: Choose whether to create a new note, write to an existing note, or use advanced options
- Preview your form in real-time
- Save and test your form
Type any of these commands:
/builder/buildform/📝 Forms: Form Builder/Editor
-
Launch 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:
- Text Input - For entering short, single-line text (project name, description, etc.)
- Textarea - For longer text entries, potentially multiple lines of text
- Number - For numeric values
- Switch - For yes/no (true/false) options
- Dropdown - For selecting from a list
- Date Picker - For selecting dates
- Note Chooser - For selecting a note
- Folder Chooser - For selecting a folder
- And many more...
-
Configure Each Field: Click on a field to edit:
- Label: What the user sees
- Key: Internal name (auto-generated, usually don't need to change)
- Description: Help text below the field
- Default Value: Pre-filled value
- Required: Must be filled out
- Compact Display: Show label and field side-by-side on one line (default is label above, field below)
-
Configure Form Output (left sidebar under "Form Settings"):
Option 1: Create New Note (most common)
- Choose "Create New Note" as processing method
- Set "New Note Title" template (e.g.,
<%- projectName %>) - Choose folder where notes should be created
- Define the note content template
Option 2: Write to Existing Note
- Choose "Write to Existing Note" as processing method
- Specify target note (
<today>for today's note, or a specific note title) - Choose where to write (append, prepend, under a heading)
- Define the content template
-
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:
- New Note Title: Use form fields in the title like
<%- projectName %> - Folder: Where to create the note (can use
<select>to choose each time) - Space: Private or a specific Teamspace
- Note Content: Write a template using form fields like:
# <%- projectName %> **Start Date:** <%- startDate %> **Team:** <%- team %> ## Description <%- description %>
Perfect for: Adding to today's note, logging entries, appending to project notes, etc.
Configuration:
- Target Note:
<today>- Today's daily note<current>- Currently open note<choose>- Prompt to choose note each time- Specific note title
- Write Location: Where to add content
- Append - Add to end of note
- Prepend - Add to beginning of note
- Under Heading - Add under a specific heading
- Content Template: What to write using form fields
- Start Simple: Create a form with just 2-3 fields first to learn how it works
- Use Descriptions: Help text makes forms easier to use
- Test Early: Use "Open Form" button frequently to test as you build
- Use Headings: Group related fields with heading elements
- Add Separators: Visual dividers help organize long forms
- Preview Updates Live: The preview pane shows changes as you make them
Method 1: Command Bar (easiest)
- Type
/formor/dialog - Select your form from the list
- Fill out and submit
Method 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.triggerOpenFormView 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:
- Browse available forms
- Preview form details
- Launch forms directly
- Edit forms in Form Builder
The Form Builder includes these field types:
- Text Input - Single-line text
- Textarea - Multi-line text (expandable)
- Number - Numeric input with +/- buttons
- Read-only Field - Display-only text
- Dropdown - Select from a list
- Switch - Toggle on/off
- Button Group - Choose one option from buttons
- Date Picker - Calendar for selecting dates
- Note Chooser - Search and select a note (supports single or multi-select with configurable output format)
- Folder Chooser - Search and select a folder
- Space Chooser - Select Private or a Teamspace
- Heading Chooser - Select a heading from a note
- Event Chooser - Select a calendar event
- Tag Chooser - Select multiple hashtags
- Mention Chooser - Select multiple @mentions
- Frontmatter Key Chooser - Select values from frontmatter keys across notes
- Heading - Section title
- Separator - Horizontal divider line
- Text - Instructions or descriptions
- Markdown Preview - Display formatted markdown content
- Table of Contents - Clickable links to form sections
- Hidden Field - Store data without displaying it
- JSON Editor - Edit JSON data
- Button - Clickable action button
- Autosave - Auto-save form progress
- TemplateJS Block - Execute JavaScript code (advanced)
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)
- When enabled, all forms automatically save progress every 30 seconds
- Protects against data loss from crashes or accidental closes
- Autosave files are stored in @Trash folder
You can disable this globally and add autosave to specific forms only if preferred.
- Start with the Form Builder - Don't try to edit JSON manually
- Test frequently - Use the "Open Form" button to test as you build
- Use meaningful field labels - Clear labels make forms easy to use
- Add descriptions - Help text prevents confusion
- Set good defaults - Pre-fill common values to save time
- Group with headings - Organize long forms with section headings
- Use conditional fields - Hide advanced fields until needed (use
dependsOnKey) - Create separate forms for different use cases - Don't try to make one giant form do everything
- Check Plugin Console (NotePlan → Help → Plugin Console) for errors
- Try re-saving the form in Form Builder
- Make sure the form template has
type: template-formin frontmatter
- Check your output configuration in Form Builder
- For "Create New Note": Verify folder path and note title template
- For "Write to Existing Note": Verify target note exists
- Check Plugin Console for error messages
- Close and reopen Form Builder
- Check Plugin Console for details
- Try creating a new simple form to test
- Check @Trash folder for autosave files
- Use
/restoreautosavecommand - Enable autosave in plugin settings if it's disabled
Most 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: trueWhen preloadChooserData: true is set, the form will preload all chooser data when the HTML file is created:
- Folders - All folders for folder-chooser fields
- Notes - All notes for note-chooser fields
- Teamspaces - All teamspaces for space-chooser and folder-chooser decoration
- Mentions - All mentions for mention-chooser fields
- Hashtags - All hashtags for tag-chooser fields
The preloaded data is embedded in the saved HTML file (form_output.html), allowing you to:
- Test the form in Chrome without NotePlan
- Debug CSS and layout issues
- Share static HTML files for design review
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:
- Complex conditional logic beyond what Form Builder supports
- Advanced date/time calculations
- Integration with other plugins
- Custom note structure generation
Creating a Processing Template:
- Run
/createprocessoror/newprocessor - Follow the wizard to set up basic configuration
- Edit the template to add custom logic using EJS templating
Processing 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.
Dynamic Template Selection:
You can allow users to choose which processing template to use by adding a note-chooser field with the key receivingTemplateTitle to your form. This enables dynamic template selection at form submission time.
How it works:
- Add a
note-chooserfield to your form - Set the field's
keyto exactlyreceivingTemplateTitle - When the form is submitted, the selected note's title will be used as the processing template
- If no template is selected in the form field, the system falls back to the
receivingTemplateTitleset in the form's frontmatter (if present)
Example form field definition:
{
"type": "note-chooser",
"key": "receivingTemplateTitle",
"label": "Choose Processing Template",
"includePersonalNotes": true,
"includeTemplatesAndForms": true,
"startFolder": "@Templates",
"includeRegex": "^Template",
"description": "Select which template should process this form submission"
}Use cases:
- Allow users to choose between different processing templates (e.g., "Meeting Template" vs "Project Template")
- Create a single form that can route to different processing templates based on user selection
- Enable dynamic workflow routing based on form data
Note: The form must have processingMethod: "form-processor" set in its frontmatter. The receivingTemplateTitle field value takes precedence over the frontmatter value when a template is selected in the form.
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:
- form-processor - Uses a custom processing template (advanced)
- create-new - Creates a new note (handled by Form Builder)
- write-existing - Writes to existing note (handled by Form Builder)
- run-js-only - Executes JavaScript only (advanced, requires TemplateJS Block fields)
You typically don't need this - use Form Builder instead!
Form templates are stored as NotePlan notes with:
type: template-formin frontmatter- A
formfieldscode block with JSON array of field definitions - Optional launch links (auto-generated by Form Builder)
See the end of this document for complete JSON field reference if you need to edit manually.
For executing custom JavaScript during form processing:
- Add a "TemplateJS Block" field in Form Builder
- Write JavaScript code that executes when form is submitted
- Useful for: creating folders, moving files, custom data 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,createMissingHeadingwindowTitle,formTitlewidth,height,hideDependentItems,allowEmptySubmit,title
Exception: receivingTemplateTitle can be used as a field key if you want to allow users to dynamically select the processing template. See "Dynamic Template Selection" in the Custom Processing Templates section above.
Note: 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 space
space-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...'
}
]
```- np.Templating Plugin - For advanced template processing
- np.CallbackURLs Plugin - For creating x-callback-url links easily