Formulas and helper functions

The complete reference for Droplet's formula language: where formulas run, every operator and helper function, the limits to know, and a library of copy-and-paste recipes.

Formulas and helper functions

A formula is a JavaScript expression that Droplet evaluates against your form's live data. Every field is available by its ID, and the result drives a Computed field, a validation check, a Show/Hide rule, and more. This is the single home for the formula language. For the components that use formulas, see Use computed and identifier components.

Where formulas run

Computed fields
The most common place. A Computed field shows the result of a formula and recalculates live as other fields change.
Validation rules
A formula that must evaluate to true before the form can be submitted. See Use Validation Rules.
Show/Hide Field Rules
A formula that decides whether a field or section is visible. See Use Show/Hide Field Rules.
Default values, dynamic options, and IDs
Pre-fill a field, drive a Dropdown's options from a dataset, or format an Identifier, all with formulas.
Workflow routing and assignment
Conditional step routing and dynamic approver assignment evaluate formulas too. See Configure workflows.

Reference fields by ID

Inside a formula, every field is a variable named by its ID (find it under Details in the Properties panel). A Computed field labeled "Total" with the formula quantity * unitPrice multiplies the field whose ID is quantity by the one whose ID is unitPrice.

Inside a Table, use getCell(columnId) to read another column in the same row, and sum(columnId) to total a whole column.

Operators and building blocks

Math
+ add, - subtract, * multiply, / divide, % remainder. The full Math object is available too (Math.round(), Math.max(), Math.ceil()).
Comparison
=== equal, !== not equal, > < >= <=. Always use triple ===, not a single = (which assigns).
Logic
&& and, || or, ! not. Use the double && / ||, not single characters.
If-else (ternary)
condition ? valueIfTrue : valueIfFalse. For example, score >= 80 ? 'Pass' : 'Fail'.
Nested ternary
Chain them for more than two outcomes: score >= 90 ? 'A' : score >= 80 ? 'B' : 'C'.
IIFE (multi-step logic)
When one line is not enough, wrap a block in an Immediately Invoked Function Expression: (() => { /* variables, if/else, loops */ return result })(). See the library below for examples.

Helper function reference

Droplet ships built-in helpers on top of standard JavaScript. Here is the full set, by category.

Math and numbers

sum(...)
Add values together: sum(fieldA, fieldB, fieldC). Pass a single table column ID to total the column: sum(lineTotal).
multiply(a, b)
Multiply values: multiply(quantity, price).
toCurrency(n) / fromCurrency(s)
Convert between a number and a currency string ("$1,234.56"). Always fromCurrency() before doing math on a currency value, then wrap the result in toCurrency().
value.length
The character count of a text field, or the number of items in a list/checkbox field.

Comparison and logic

equals(a, b) / notEquals(a, b)
Compare two values: equals(status, 'Approved'), notEquals(role, 'guest').
isGreaterThan(a, b) / isLessThan(a, b)
Compare numbers: isGreaterThan(amount, 1000), isLessThan(age, 18).
withinRange(value, min, max)
True when a value falls inside a range: withinRange(studentAge, 5, 18).
includes(array, value)
True when an array contains a value: includes(['UT','NY','MA'], state).

Text and formatting

String(value)
Convert a number to text: String(amount).
padStart(string, length, pad)
Pad a string to a fixed length: padStart(String(getSequenceId()), 5, '0') produces "00001".
Template literals
Backtick strings with ${ } interpolation are supported: `Invoice ${invoiceNumber}`.

Workflow and submission

currentStep()
The ID of the current workflow step: currentStep() === 'completed'.
getStepIdsAndLabels()
An array of the workflow's steps as { id: label } objects, for example [{"start": "Start"}, {"completed": "Completed"}].
submittedByName() / submittedByEmail()
The name and email of the person who started the submission.

Tables, data, and IDs

getCell(columnId)
Inside a Table column formula, the value of another column in the current row: getCell(quantity) * getCell(unitPrice).
Object.keys(dataset)
Read keys from a dataset (datasets are available by name): Object.keys(schools).sort().
getSequenceId()
An auto-incrementing number, used to build unique identifiers.

Validation

isOptional()
Marks a field as not required, useful for conditional validation: equals(nextAction, 'Approve') ? value : isOptional().

Limits and lore

A few things that trip people up:

  • A formula is an expression, not a script. For multiple steps, variables, or branching, wrap it in an IIFE (see above).
  • new Set() is not available in the Droplet runtime. To de-duplicate, use filter() with indexOf() or build an object keyed by value.
  • Standard Array, Object, Math, String, and Date methods work, plus template literals.
  • Currency fields are strings. "$1,200.00" is text, so fromCurrency() it before math, then toCurrency() the result.
  • Operators bite. = assigns, === compares. & and | are bitwise; you almost always want && and ||. If a formula misbehaves, check these first.
  • Dates and time zones. Parse with an explicit time to avoid off-by-one days: new Date(startDate + 'T00:00:00').
  • Hidden does not mean cleared. A hidden field keeps its value and still submits, unless its "clear when hidden" option is on.
  • Computed is read-only. Computed, Identifier, and Timestamp fields cannot be made editable, by design.

Formula library

Copy these into a Computed field's formula (or a validation/Show-Hide rule) and swap in your own field IDs.

Combine a full name

firstName + ' ' + lastName

Line total in a table (per row)

getCell(quantity) * getCell(unitPrice)

Grand total across a table column

toCurrency(sum(lineTotal))

Mileage reimbursement

toCurrency(miles * 0.67)

Pass or fail from a score

score >= 80 ? 'Pass' : 'Fail'

Letter grade (nested ternary)

score >= 90 ? 'A' : score >= 80 ? 'B' : score >= 70 ? 'C' : 'F'

Tiered discount (IIFE)

(() => {
  const subtotal = fromCurrency(amount)
  if (subtotal >= 10000) return toCurrency(subtotal * 0.85)
  if (subtotal >= 5000)  return toCurrency(subtotal * 0.90)
  return toCurrency(subtotal)
})()

Days between two dates

(() => {
  if (!startDate || !endDate) return ''
  const a = new Date(startDate + 'T00:00:00')
  const b = new Date(endDate + 'T00:00:00')
  return Math.round((b - a) / 86400000)
})()

Auto-updating school year

(() => {
  const now = new Date()
  const y = now.getFullYear()
  return now.getMonth() >= 6 ? `${y}-${y + 1}` : `${y - 1}-${y}`
})()

Padded reference number (EXP-00042)

`EXP-${padStart(String(getSequenceId()), 5, '0')}`

Look up an approver's email from a dataset

budgetCodes[budgetCode]['Approver']['email']

Count selected checkboxes

value.length

Conditional summary message

isGreaterThan(fromCurrency(total), 5000)
  ? 'This request needs director approval.'
  : 'This request routes straight to your manager.'

Validation recipes

Email must be on your domain

includes(submittedByEmail, '@yourschool.org')

Require a checkbox to be checked

value === true

Table rows must add up to the contract total

sum(amount) === fromCurrency(contractTotal)

Only require a field on approval

equals(nextAction, 'Approve') ? value : isOptional()
Pair these with the components that run them: computed and identifier components, validation rules, Show/Hide rules, and datasets.
Last reviewed by Nick Duell and published on June 23, 2026 7AM ET