Placeholders & tokens
The unified placeholder model, {Field} form values, item["Field"] stored values, and [System] tokens, with an example for every field type.
SharePoint Forms365 has one placeholder model, used everywhere you reference a
value, visibility / enable / required rules, calculated values, validation,
display text, default values, and Set-field-value save rules. There are exactly
three sigils, each with a single meaning, and each mirrors a f365.* call you can
use from code. Learn these three and you can read any value anywhere.
The three sigils
| Property | Description |
|---|---|
{Field}value on the form | The current value of a field placed on this form (what the user has entered). Code: f365.field("Field").value |
item["Field"]stored list-item value | The actual SharePoint value for ANY column, even one not on the form, in SP-native shape. Supports member access. Code: f365.item["Field"] |
[Today] [Me] [ID]system / context token | A built-in value: the date, the signed-in user, the item id, and more. Code: f365.context / f365.user.current(). See all system tokens → |
Where each sigil works
Not every surface accepts every sigil. Conditions are full expressions; display and template surfaces are simple text interpolation.
| Property | Description |
|---|---|
Visible / Enable / Required if{Field} · item["Field"] · [Today] [Me] | Full expression. Member access allowed. |
Conditional formatting (When){Field} · item["Field"] · [Today] [Me] | Full expression; styles the element while true. See Rules → Conditional formatting. |
Calculated value{Field} · item["Field"] · [Today] [Me] | Full expression that returns a value. |
Custom validation{Field} · item["Field"] · $value | Expression; $value is this field’s value. |
Display text / header / HTML{Field} · [System] | Text interpolation, no item["…"] here; use {Field}. |
Default value{Field} · [System] | Text interpolation on New forms. |
Set-field-value template{Field} · [System] | Text interpolation, incl. post-save [ID] / [GUID]. |
Document library folder template{Field} · [System] | Text interpolation, one folder level per /. A blank value pauses the upload; [ID] resolves once the item is saved. See Document Library field. |
Lookup display template{Column} | The one exception, {Column} here is a column on the picked SOURCE-LIST row, not a form field. See Lookup field → Display template. |
Field on form
{Field} is the value of a field placed on the form, the live form-control
state, which reflects edits the user just made. Reference fields by SharePoint
internal name, not the display label. Optional :modifiers format the value
or pick a sub-property:
| Property | Description |
|---|---|
{Title} | The field value as text. |
{DueDate:short}short · long · friendly | Date formatting (locale short / long / “2 days ago”). |
{Owner:Title}:Title · :Email · :Id | Pick a sub-property of a person / lookup value. |
{Amount:raw}:raw | The unformatted underlying value. |
{Qty:000}:0000 | Zero-pad a number to a fixed width (7 becomes 007). Zero padding → |
{Field} only resolves for fields actually on the form. For any other column, or to keep the SP-native typed shape, use item["Field"].
Item record
item["Field"] reads the stored SharePoint list-item value for any column,
whether or not it is on the form. The value keeps its SharePoint-native shape, so
multi-value and complex columns retain their structure and you can drill in with
.property and [index]:
Member access into stored values
item["Project"].LookupId == 5
item["Manager"].Email == "boss@contoso.com"
item["Tags"][0] == "Urgent"
item["Reviewers"][0].Email
Notes:
- Always quote the column name:
item["Field"]. Unquoteditem[Field], dotteditem.Field, and bareFieldare legacy and auto-migrated to the quoted form. - On a New form there is no saved item yet, so
item["Field"]is empty for most columns and a rule using it evaluates false, that's expected. On Edit / Display it reads the stored value as loaded. - In rules,
item["Field"]does not change while the user edits the form, only a save updates it. That makes it the right choice for "lock after approval" patterns:enableIf: item["Approval Outcome"] != "Approved"keeps the section editable during the edit session (even after the user picks Approved) and locks it on the next open once the item is saved as Approved. Use{Approval Outcome}instead when the rule should react instantly as the user changes the value. item["Field"]returns the same shape as the code API'sf365.item["Field"].
System tokens
System tokens use square brackets and a fixed vocabulary. They work in display text, default values, and Set-field-value templates (and the date / user ones in conditions too).
| Property | Description |
|---|---|
[Me][Me:Title] [Me:Email] [Me:Login] [Me:Id] | The signed-in user (whole persona, or a single field). |
[Today][Today+N] [Today-N] [Today:dd-MM-yyyy] | Today’s date, with optional day offset or custom format. |
[Now][Now:HH:mm] | Current timestamp; custom time/date patterns supported. |
[ID] / [ItemId][ID+N] [ID-N] [ID:0000] | The item id (empty on a New form until saved), optionally with a numeric offset and/or a zero-pad mask. Zero padding → |
[Offset][ID-[Offset]] | A Set-field-value rule’s own Offset number, set per rule (or worked out with Determine offset). Only save rules have one. Rule offset → |
[Seq][Seq:0000] | A running number for Set-field-value rules: the newest item’s number in the rule’s format, plus one. Sequence numbers → |
[GUID] | The item’s SharePoint GUID (resolved after save, in Set-field-value rules). |
[QueryString:param] | A value from the page URL query string. |
[FormId] | The form’s id / GUID. |
[DisplayMode] | new · edit · display. |
[FormVersion] [BuildVersion] | The form schema version; the runtime build number. |
[Created] [Modified][CreatedDate] [UpdatedDate] | Item created / modified timestamps. |
[Author] [Editor][CreatedBy] [UpdatedBy] | Item creator / last editor. |
Custom date patterns (for [Today:…] / [Now:…] and {DateField:…} is named
only): yyyy yy MMMM MMM MM M dd d HH H hh h mm m ss s a ZZ Z. Example, [Today:dd-MM-yyyy] → 04-06-2026.
ZZ renders the reader's UTC offset (+10:00) and Z the short zone name (AEST, GMT+10).
Add one of them whenever the value is a record of when something happened rather than a date on
screen, because a bare time is ambiguous as soon as somebody reads it from another country.
Example, [Now:yyyy.MM.dd HH:mm:ss ZZ] → 2026.07.29 08:27:19 +10:00.
System tokens in display text & templates
Logged by [Me:Title] on [Today]
Reference: REF-[ID]
Invoice no: INV-[ID+1000]
Due in 14 days: [Today+14]
Project [QueryString:proj]
[ID] accepts a whole-number offset, the same way [Today] accepts a day
offset: [ID+1000] on item 42 gives 1042, and [ID-5] gives 37. Use it when
a reference number has to start from a base other than 1, for example an invoice
series that begins at 1001. Two things to know. The offset is plain arithmetic,
so a subtraction larger than the id produces a negative number rather than being
clamped. And on a New form the id does not exist yet, so [ID+1000] renders
empty in display text; inside a Set-field-value rule the runtime saves first,
then re-resolves and patches the item, so the stored value is correct.
Rule offset
A common reference style runs a fixed distance behind the item id, usually
because the numbering was carried over from an older system: item 72 is
ACT-43, item 73 is ACT-44, and so on. The gap here is 29, so
ACT-[ID-29] would work, but every Set-field-value rule also has an Offset
box (under Insert token) so the number lives in one obvious place.
Put [ID-[Offset]] in the value template and the rule substitutes its own
Offset before the id is worked out:
Reference that runs behind the item id
Value template: ACT-[ID-[Offset]]
Offset: 29
// item 72 -> ACT-43
Value template: ACT-[ID-[Offset]:0000]
// item 72 -> ACT-0043
Determine offset (next to the Offset box) works the number out for you. It
reads the newest items in the list, takes the most recent one whose target field
already holds a number, and subtracts: item 71 holding ACT-42 gives 29. The
number is the last run of digits in the value, so 2026-ACT-42 reads as 42. It
also tells you how many of the recent items fit the same offset, so a series that
was renumbered part way through is easy to spot.
Things to know:
- An empty Offset counts as 0, so
[ID-[Offset]]is just the id. The rule editor warns you when the template uses[Offset]with the box empty. - A negative offset is fine. If the references run ahead of the ids (item 5
is
INV-1005), Determine offset gives -1000 and[ID-[Offset]]becomes[ID+1000]. - Deleted items leave gaps. SharePoint never reuses an id, so if item 72 is
deleted the next new item is still 73 and gets
ACT-44. - It is a save-rule feature.
[Offset]belongs to a Set-field-value rule. In display text and default values there is no offset, so it renders empty.
Sequence numbers
When a reference should simply count up (VEH-1, VEH-2, VEH-3) without being tied
to the SharePoint item id, use [Seq] in a Set-field-value rule:
A running reference number
Value template: VEH-[Seq] // VEH-9 is the newest -> VEH-10
Value template: VEH-[Seq:0000] // VEH-0009 is newest -> VEH-0010
Value template: {Site}-[Seq] // one series per site: North-4, South-12
Every time a new item is saved, Forms 365 finds the newest item in the list whose value is in the rule’s format, and adds one. The number is written in the same save, so there is no second save. The item id plays no part, so a deleted item does not leave a gap.
The number is worked out on the Forms 365 server, which reads the whole list with its own app access. What the person saving can see plays no part, so it is correct even on lists where people can only read their own items.
[Seq] is never left empty. If the number can’t be worked out (the server
can’t be reached or its access isn’t approved, or none of the newest 5,000 items
has a value in the rule’s format), Forms 365 counts the items in the list and
uses that count plus one. If even the count can’t be read, the number is 1. A
Next number you have set is still the lowest it will use.
The rule’s format decides what counts. For VEH-[Seq:0000], VEH-9,
VEH-0009 and VEH-10 all count, while Vehicle 12 or a blank are skipped.
Field placeholders are filled in first, which is what gives {Site}-[Seq] a
separate series for each site. Use exactly one [Seq] per template.
Next number (override). In the rule editor, type a number under Next number and click Set. The next new item gets that number, and the rest carry on from it. It works upwards (jump from VEH-42 to VEH-500) and downwards (restart at 1). Set a new number any time; the latest one wins. Preview next shows what the next item will get, read from the live list. Click Save to keep it, and publish the form for form rules.
Things to know:
- On Edit, an item keeps its number. Re-saving never renumbers it. An item with no number yet gets the next one.
- Restarting lower repeats numbers unless the format changes. For a new
year, put the year in the format, for example
VEH-2027-[Seq:0000]. - Deleting the newest item makes its number come round again, because the next save continues from the newest item that is left.
- Two people saving at the same moment get different numbers. The server holds each number it hands out for a few minutes, and the form double-checks right after saving.
- It needs Forms 365’s API access approved in your SharePoint admin centre (the same approval the AI and saved-signature features use). Without it, saves still go ahead but fall back to the item count plus one, which can repeat a number if items have been deleted, and two people saving at the same moment can get the same one.
- Items created outside Forms 365 (Power Automate, imports) don’t get a number, and are skipped when working out the next one.
- Rows added through a linked list are numbered too, by the list’s global rules. The number is given when the parent form saves and the row is written, not when the row is filled in, so a cancelled parent uses no number. If the server can’t give a number, the row gets the child list’s item count plus one, so it is never saved without a number. A row being edited keeps its number.
- A
[Seq]rule on a linked-list row form’s own rules isn’t supported, and saving the row says so. Put the rule on the list’s global rules instead.
Zero padding numbers
To get a fixed-width reference like Tag-0001 instead of Tag-1, put a mask
of zeros in the modifier slot. The number of zeros is the number of digits you
want:
Zero-pad a reference number
Tag-[ID:0000] // item 42 -> Tag-0042
Tag-[ID-9:0000] // item 10 -> Tag-0001
INV-[ID+1000:000000] // item 42 -> INV-001042
Q{Qty:000} // Qty = 7 -> Q007
It works anywhere a value is interpolated: display text, headers, custom HTML,
default values, and Set-field-value templates. It reads the same way
[Today:dd-MM-yyyy] does, the modifier is a format pattern for the value, so
there is no new token to learn and it composes with an [ID] offset.
Four behaviours worth knowing, all of them chosen so a mask can never quietly corrupt a value:
- It never truncates. A number wider than the mask comes through in full, so
[ID:0000]on item 123456 gives123456. Shortening an id would break the very reference you are building. - The sign sits outside the padding.
[ID-20:0000]on item 5 gives-0015, because the offset is deliberately not clamped and a mis-sized offset should be visible. - A blank value stays blank. An empty field under a mask renders empty, not
0000. Same for[ID:0000]on a New form, where the id does not exist yet. In a Set-field-value rule the runtime saves first and then patches the real padded value in. - Non-numbers pass through untouched.
{Status:0000}on "Open" is just "Open". A mask only ever affects a number.
A mask is recognised only when the modifier is entirely zeros, so it can never
be confused with a date pattern (dd-MM-yyyy), a sub-property pick
({Owner:Title}), or :raw.
Per field type
What {Field} (form value) and item["Field"] (stored value) give you, by
SharePoint column type:
| Property | Description |
|---|---|
Single line / Note / Email / Phone / URL{F} → "Acme" | item["F"] → "Acme" (string) |
Number / Currency{F} → "42" | item["F"] → 42 (number) |
Date / DateTime / Time{F:short} → 4/06/2026 | item["F"] → "2026-06-04T00:00:00Z" (ISO) |
Choice (single){F} → "Open" | item["F"] → "Open" |
Multi-choice{F} → "A, B" | item["F"] → ["A", "B"] |
Yes/No (boolean){F} → "true" | item["F"] → true |
Lookup (single){F} → "Project X" | item["F"] → { LookupId, LookupValue } · item["F"].LookupId |
Lookup (multi){F} → "X, Y" | item["F"] → [{ LookupId, LookupValue }, …] |
Person (single){F} → "Ada Lovelace" | item["F"] → { Id, Title, Email, LoginName } · item["F"].Email |
Person (multi){F} → "Ada, Alan" | item["F"] → [{ Id, Title, Email, LoginName }, …] |
Managed metadata (taxonomy){F} → "Marketing" | item["F"] → { Label, TermGuid, WssId } · compare on TermGuid |
Managed metadata (multi){F} → "Marketing, Sales" | item["F"] → [{ Label, TermGuid, WssId }, …] |
Rating{F} → "4" | item["F"] → 4 |
Hyperlink{F} → "https://…" | item["F"] → { Url, Description } · item["F"].Url |
Geolocation | item["F"] → { Latitude, Longitude } |
Location | item["F"] → { DisplayName, Street, City, State, CountryOrRegion, PostalCode } |
Rich text{F} → text/HTML | item["F"] → raw HTML |
Likert | item["F"] → JSON of { row: value } |
Hidden{F} → "x" | item["F"] → "x" |
Attachments / Image / Signature / Linked list | Written by post-save writers, not read through {F} / item["F"]; use the control API. |
Lookup & person columns
Equality unwraps the value, so the natural comparisons work on either the form value or the stored value:
Compare a lookup / person by title or id
{Project} == "Project X" // by display title
item["Project"].LookupId == 5 // by id (stored value)
item["Manager"].Email == "a@b.com" // a person sub-property
contains({Reviewers}, "Ada") // multi-person contains a name
"Is this the current user?", compare a person field to [Me]. This is the
recommended check: [Me] matches on whatever identifier the two values share
(login → id → email → title), so it works even before the form is saved,
when a freshly-picked person has no numeric Id yet. Prefer it over == [Me:Id]
(the Id is null until save) or == [Me:Title] (display names can collide).
Match the signed-in user
{Manager} == [Me] // the picked person IS the current user
{Manager} != [Me] // ...is NOT the current user
Multi-value columns
Multi-choice and multi-lookup/person are arrays in item["…"]:
Multi-value checks
item["Tags"][0] == "Urgent" // first tag
contains({Tags}, "Urgent") // any tag is "Urgent"
item["Reviewers"][0].Email // first reviewer’s email
Conditions and expressions
Visibility, enable, required, and validation rules (and calculated values) are boolean / value expressions over the three sigils.
| Property | Description |
|---|---|
Comparison== != <> > >= < <= | Equality unwraps lookups/people, so {Project} == "X" matches the title. |
Logicaland or not (&& || !) | Combine conditions. Word or C-style forms both work. |
FunctionsisEmpty() isFilled() contains() startsWith() endsWith() | Predicates on a field or item value. |
Membershipx in y | True when x is an element of array y. |
Arithmetic+ - * / % | For calculated values; + on text concatenates. |
Semantics worth knowing:
- Empty,
"",null, and empty arrays are all “empty”;isEmpty()/isFilled()and== nulltest for it. - Numbers from the form arrive as strings;
+adds when both sides are numeric, otherwise concatenates (use{A} + "" + {B}to force text). - Lookups / people compare by title or id automatically;
contains()works against the picked set of a multi-value field.
Condition examples
{Status} == "Complete" and {Amount} > 1000
item["Region"] == "APAC" or {Priority} == "High"
isFilled({Manager}) and item["ApprovalStage"] != "Pending"
{Country} in ["AU", "NZ"]
See Expression grammar for the full operator / precedence reference.
Calculated values
A calculated value is an expression that returns a value, recomputed on load and whenever a referenced field changes.
Calculated value examples
{Price} * {Qty}
{First} + " " + {Last}
{Subtotal} + item["TaxAmount"]
Validation rules
The field is valid only when the expression is true (checked at save). Use
$value for the field’s own value, and set a custom message for failures.
$value is specific to this rule: it is the one place a field can refer to
itself without naming itself. Everywhere else (Visible if, Enable if, Required
if, Calculated value) use {Field} with the field’s internal name. If a
validation rule cannot be parsed, it is skipped rather than blocking the person
filling in the form, so use the Validate button to confirm a rule is well formed.
Validation examples
$value > 0
{End} >= {Start}
contains($value, "@")
Default values & save templates
Default values (New forms) and Set-field-value templates are text
interpolation, use {Field} for a form value and [System] tokens.
item["…"] is an expression concept and is not interpolated here.
Template examples
Created by [Me:Title] on [Today]
{Subject}, {Site}
REF-[ID] // [ID]/[GUID] resolve after save in Set-field-value rules
Only run if, gating a Set-field-value rule
A Set-field-value rule (on a form, or a global list rule that covers every form on the list) can carry an Only run if condition. It is built with the same panel as a field's Visible if rule, uses the same grammar as everything in Conditions and expressions, and the rule only writes when it comes out true. Leave it blank and the rule runs every time, exactly as it always has.
The common one is "fill this in, but never overwrite it":
Only fill the target when it is still blank
Target field: Ref
Value template: REF-[ID]
Only run if: isEmpty({Ref}) // Ref is on the form
Only run if: isEmpty(item["Ref"]) // Ref is a column, not on the form
Which of those two you want is the one thing worth pausing on, and the condition panel has an on the form / stored value picker for exactly this choice:
{Ref}reads the value on the form, what the person filling it in can see and type.item["Ref"]reads the value stored in SharePoint, and works for any column in the list including one the form does not show.
If the column is not on the form, {Ref} is always empty, so a guard written
that way always passes and the rule always overwrites. Use item["Ref"] there.
A global list rule lists every column in the list, so most of its choices are
off-form ones. The Only if X is blank button next to the panel fills in the
right form for you based on the target field you picked.
A condition that cannot be parsed causes the rule to be skipped, not run. That is deliberate: a broken guard must not turn into an accidental overwrite.
Person / group fields are the one exception to "default values are text". Their default resolves to an actual user, not a string. Two forms are accepted:
- a single
[System]token,[Me](the signed-in user) or[Author]; or - a specific user's login / email, e.g.
linda.oswald@beeng.com.au(or a claims logini:0#.f|membership|…). It's looked up and shown as a normal chip once the form loads.
The default applies only on New; on Edit / Display the saved value shows
instead. Plain text (a display name) and {Field} references aren't valid people
values and are ignored.
Default a people field, current user, or a specific person
Default value: [Me] // the signed-in user
Default value: linda.oswald@beeng.com.au // a specific user (login / email)
Date availability rules
On a Date or Date & Time field you can restrict which days can be picked. Open the field's properties and use the Available dates panel. The calendar greys out (and blocks) every disallowed day, and the form also rejects a disallowed value on save, so the rule can't be bypassed by typing or a default value.
Rules combine with AND: a day is selectable only when it passes every rule you've set.
| Property | Description |
|---|---|
Earliest dateToday / N days from today / fixed date | Lower bound. “Today” gives the classic “only on or after today”. Offsets track the calendar (e.g. +1 = from tomorrow, -7 = within the last week). |
Latest dateToday / N days from today / fixed date | Upper bound. e.g. “+30 days” = bookings at most a month out. |
Exclude weekdaysSun…Sat toggles | Grey out whole weekdays. The “Exclude weekends” shortcut toggles Sat + Sun together. |
Advanced ruleJavaScript predicate | Anything the toggles can’t express. See below. |
Advanced rule (JavaScript)
For rules the toggles can't express, "not the 1st of the month", "only
Mondays", "every other Friday", write the body of a predicate. It receives
date (a JavaScript Date) and a helpers object, and returns true when the
date should be selectable (returning false greys it out).
Advanced predicate examples
// No 1st of the month
return !helpers.isFirstOfMonth(date);
// Only Mondays
return helpers.dayOfWeek(date) === 1;
// Weekdays within the next 14 days only
return helpers.isWeekday(date) && date <= helpers.addDays(helpers.today, 14);
helpers provides: today, dayOfWeek(d), isWeekend(d), isWeekday(d),
addDays(d, n), startOfMonth(d), endOfMonth(d), isFirstOfMonth(d),
isLastOfMonth(d), dayOfMonth(d).
Code equivalents
The no-code sigils map one-to-one onto the f365.* JavaScript API:
| Property | Description |
|---|---|
{Field}f365.field("Field").value | The value on the form. Throws if the field is not on the form, use f365.item for off-form. |
item["Field"]f365.item["Field"] | The stored list-item value (any column). Same shape as no-code item["Field"]. |
(non-field control)f365.control("Name") | Linked-list and other non-field components. |
[Me] / [Me:Title]f365.user.current() / .title | The signed-in user. |
[ID] [DisplayMode] [FormId]f365.context.itemId / .displayMode / .formId | Form context. |
See the f365 field API and context API for the full surface.
Common patterns
Show a section only when an off-form column has a value
Visible if: item["ApprovalStage"] == "Approved"
Require a justification only for large amounts
Required if: {Amount} > 10000
Stamp who/when on save (Set-field-value rule)
Target: LoggedBy Template: [Me:Title]
Target: LoggedAt Template: [Now]
Rules & gotchas
- Brackets are system-only.
[Field]will not read a field, use{Field}oritem["Field"]. - Internal names, not display labels. All references use the SharePoint
internal name (e.g.
OData__Comments), which never changes. - New forms have no item.
item["…"]is empty until the item is saved. - Display / default / template surfaces interpolate
{Field}+[System]only, they do not evaluateitem["…"]expressions. - Legacy syntax is migrated. Opening an old form upgrades
[Field]→{Field},item.Field→item["Field"], etc.; Save to persist.
Related
Related articles
- Expression grammar
The rule language behind Visible if, Enable if, Required if, Calculated value and custom validation. Parsed to an AST, evaluated safely, never with eval.
- visibleIf, conditional visibility
Hide or show any field, section, or button based on the value of other fields. Express the condition once; the runtime evaluates it on every change.
- enableIf, conditional enable/disable
Grey out a field unless an expression returns true. The field stays visible, just locked from editing.
- requiredIf, conditional required
Mark a field required only when another field has a specific value.
- Validation, schema, expression, and author-defined
Three layers of field validation, when each runs, and how errors surface in the UI.