Code
Cards and Buttons can have a JavaScript function.
Purpose
- Card: computing Card Totals (locally or remotely), or fetching a numeric value, e.g. Num. of Products in Stock.
- Button: for HTTP requests, e.g. posting a form (see the last example)
Function Argument (Payload)
- Card: describes the Card content.
- Button: describes its parent Card content.
When does it execute?
- Card: on File load, and on payload-relevant changes.
- Button: when clicked in Previewer.
Return Value
- Card: has to be a number (or numeric string) and becomes the Total.
- Button: is ignored.
Technical Details
Both timeout after 8 seconds. If you open a File that has a Card Code error, you'll see a spinner until it times out. Similarly, if the execution on a Button fails, and the Button has more actions, they'll execute after the timeout.
For security, functions run inside Web Workers. Therefore, there are limitations. For example, no direct DOM manipulation.
JavaScript
This example has Keys (they're explained in the next section, but take a look at them here first).

Card → Code. The JavaScript editor pre-populates a snippet that sums numeric Entries that have Keys. In this example:
function (card) { const side_a = card.byKey.side_a.value; const side_b = card.byKey.side_b.value; return side_a + side_b; }
After hitting Apply, the Total will be computed by that function. And it will recompute when the Entries change.
Key Editor
Keys are for referencing specific Cards or Entries in the payload. They don't have to be unique. If repeated, the last one wins.
View → Key Editor
Suggests Keys based on the Card Title or Entry Label.

With the Keys set.

Key Grammar
Case-sensitive and must begin with a letter. Then, they can have underscores and digits.
name
last_name
LastName2
_name
1name
last.name
Payload
The payload, the argument to be passed to the function, describes the Card and its children. Each child is a description of either an Entry, or a Nested Card.
If you want Entries or Totals from other Cards, connect them to the Card with the code. By the way, those connected targets can be Hidden in Previewer.
As hidable children show up in the payload, you can use them for API keys, tokens, etc.
Like in Formulas, Nested Cards get computed first. Therefore, their Totals are ready to use in the parent payload (asynchronous code is supported).
Tip There's a Download Payload Mock button that shows the exact argument your function will be called with.
Card (Root or Nested)
key
Stringvalue
Card Total as a NumberstringValue
Card Total as a Stringchildren
Array, in order, of the Entries and Nested CardsbyKey
Object literal to reference children directly (unordered)isNumeric
Boolean, true if the Card has a numeric Total. As Totals can only be numeric, this is like a hasTotal. But as Entries also have anisNumeric
property, this consistent naming is handy for cases like the Max example below
Entry
key
Stringvalue
Number if it's numeric; 1 or 0 if it's a Checkbox; String otherwisestringValue
struck
Boolean for Strikethroughlabel
StringisNumeric
Boolean
Examples
Sum All
function (card) { return card.children .reduce((sumSoFar = 0, child) => sumSoFar + child.value); }
That function is like Formula Presets → Sum All, but the actual preset does more checks, see the next example.
Max
Equivalent to Formula Presets → Maximum.
Ensures computing on numeric children that aren't struck. And handles when there are none by returning an empty string.
Although Nested Cards have no struck
property, it's
safe to filter it.
function (card) { const values = card.children .filter(child => child.isNumeric && !child.struck) .map(child => child.value); return values.length ? Math.max(...values) : ''; }
Count children costing 50 or more
function (card) { return card.children .filter(child => child.value >= 50) .length; }
Sum children costing over 50
function (card) { return card.children .filter(child => child.value > 50) .reduce((sumSoFar = 0, child) => sumSoFar + child.value); }
Discounts
The price gets a 15% discount if buying 10 or more, or 25% on 50+.

The Auxiliary Card code:
function (card) { const num_of_bags = card.byKey.num_of_bags.value; const base_price = card.byKey.base_price.value; const discounts = card.byKey.volume_discounts.children; let discountSoFar = 0; for (const step of discounts) if (num_of_bags >= Number(step.label)) discountSoFar = step.value; return base_price * (1 - discountSoFar); }
Examples with HTTP Requests
This zip has the server-side handlers for these examples.
HTTP Get

function (card) { const product_id = card.byKey.product_id.value; return fetch(`http://localhost:7000/in-stock-count/${product_id}`) .then(response => response.json()) .then(data => data.count) .catch(console.error); }
HTTP Post

function (card) { return fetch('http://localhost:7000/hypotenuse', { body: JSON.stringify(card), method: 'POST', headers: new Headers({ 'Content-Type': 'application/json' }) }) .then(response => response.json()) .then(data => data.hypotenuse) .catch(console.error); }
HTTP Post Button

function (card) { return fetch('http://localhost:7000/form-submit', { body: JSON.stringify(card), method: 'POST', headers: new Headers({ 'Content-Type': 'application/json' }) }) .then(() => '') .catch(console.error); }