composer
Field blocks
The 30+ field types the Composer ships with — text, number, date, select, lookup, location, geolocation, signature, file, rich media, computed — and when to use each.
12 min read · 5 sections
Text and identity
| Block | Use for | Notes |
|---|---|---|
| text | Short free-form (up to 500 chars) | Pattern validation via regex. |
| rich-text | Long-form with formatting | Sanitised server-side; images allowed. |
| Email addresses | RFC-5322 validation. | |
| phone | E.164 phone numbers | Country picker + format helper. |
| url | HTTPS links | Protocol enforcement. |
| identifier | Human-ID (ticket #, VIN, serial) | Duplicate detection at tenant scope. |
Numbers, dates, and time
- number — integer or decimal, min/max/step.
- currency — number + ISO 4217 code, rendered with locale formatting.
- percentage — 0–100 with step of 0.01.
- date — calendar picker, timezone-aware.
- datetime — calendar + time, timezone configurable.
- duration — "2h 30m" style, stored as seconds.
- date-range — start + end; validation enforces start ≤ end.
Selects, lookups, and references
- select — small static list (up to 20 options).
- multi-select — same, multi-value.
- lookup — reference a tenant-wide Lookup List (see Admin guide).
- record-reference — reference another record from any module (e.g. Incident references Asset).
- user — assign to a tenant user; respects location + role scope.
- location — tree picker from the tenant hierarchy; "descendant match" toggle.
Media and files
- file — generic upload; size and mime restrictions per field.
- image — image upload with inline crop + annotation.
- photo-capture — mobile-first: camera opens directly, GPS tag optional.
- signature — capture a signature on mobile or web; stored as SVG.
- barcode-scan — mobile camera scans UPC/EAN/QR/PDF417; desktop accepts manual input.
Computed and derived
Computed fields evaluate an expression over other field values. Supported operators: +, -, *, /, concat, if/else, now(), daysBetween(), locationAncestors(), lookupLabel(). Computed values are recalculated on every save — they never rot.
// TRIR = (recordable_injuries × 200000) / total_hours_worked
if(total_hours_worked > 0,
(recordable_injuries * 200000) / total_hours_worked,
null)