Skip to content

Latest commit

 

History

History
817 lines (627 loc) · 15.1 KB

File metadata and controls

817 lines (627 loc) · 15.1 KB
title Field Types Reference
description Complete guide to all ObjectStack field types with examples and configuration options

Field Types Reference

ObjectStack supports 35 field types covering text, numbers, dates, selections, relationships, media, calculations, and enhanced types. This guide provides practical examples for each type.

Core Text Fields

Text

Single-line text input for short strings.

import { Field } from '@objectstack/spec';

// Basic text field
name: Field.text({ 
  label: 'Full Name', 
  required: true,
  maxLength: 255,
})

// Searchable text field
account_name: Field.text({ 
  label: 'Account Name',
  searchable: true,
  unique: true,
})

Configuration Options:

  • required - Make field mandatory
  • maxLength - Maximum character limit
  • minLength - Minimum character limit
  • searchable - Enable full-text search
  • unique - Enforce uniqueness constraint
  • defaultValue - Set default value

Textarea

Multi-line text input for longer content.

description: Field.textarea({ 
  label: 'Description',
  maxLength: 5000,
  rows: 5, // UI hint for initial height
})

Email

Email address field with validation.

email: Field.email({ 
  label: 'Email Address',
  required: true,
  unique: true,
})

ℹ️ Info:
Automatically validates email format: user@domain.com


URL

Website/link field with URL validation.

website: Field.url({ 
  label: 'Website',
  placeholder: 'https://example.com',
})

Phone

Phone number field with format validation.

phone: Field.phone({ 
  label: 'Phone Number',
  format: 'international', // or 'us', 'uk'
})

Password

Secure password field with encryption.

api_key: Field.password({ 
  label: 'API Key',
  encryption: true, // Encrypt at rest
  readonly: true,
})

⚠️ Warning:
Password fields are automatically masked in UI and encrypted if encryption: true


Rich Content Fields

Markdown

Markdown text editor with preview.

documentation: Field.markdown({ 
  label: 'Documentation',
  description: 'Supports full Markdown syntax',
})

HTML

Raw HTML editor (use with caution).

html_content: Field.html({ 
  label: 'HTML Content',
  description: 'Raw HTML - sanitize before rendering',
})

⚠️ Warning:
Always sanitize HTML content before rendering to prevent XSS attacks


Rich Text

WYSIWYG editor with formatting toolbar.

notes: Field.richtext({ 
  label: 'Notes',
  description: 'Rich text with formatting, lists, links',
})

Supports:

  • Bold, italic, underline
  • Headings, lists, quotes
  • Links and images
  • Tables

Number Fields

Number

Numeric field for integers or decimals.

quantity: Field.number({ 
  label: 'Quantity',
  min: 0,
  max: 1000,
  defaultValue: 1,
})

// Decimal numbers
temperature: Field.number({ 
  label: 'Temperature',
  precision: 5, // Total digits
  scale: 2,     // Decimal places
})

Currency

Monetary value with currency symbol.

annual_revenue: Field.currency({ 
  label: 'Annual Revenue',
  precision: 18,
  scale: 2,
  min: 0,
})

Display: $1,234.56 (formatted with currency symbol)


Percent

Percentage value (0-100 or 0-1).

probability: Field.percent({ 
  label: 'Win Probability',
  min: 0,
  max: 100,
  scale: 1, // One decimal place
})

Display: 75.5%


Date & Time Fields

Date

Date picker (no time component).

due_date: Field.date({ 
  label: 'Due Date',
  defaultValue: 'today',
})

birthday: Field.date({ 
  label: 'Birthday',
  min: '1900-01-01',
  max: 'today',
})

Format: YYYY-MM-DD


DateTime

Date and time picker with timezone support.

created_at: Field.datetime({ 
  label: 'Created At',
  readonly: true,
  defaultValue: 'now',
})

Format: YYYY-MM-DD HH:mm:ss


Time

Time picker (no date component).

meeting_time: Field.time({ 
  label: 'Meeting Time',
  format: '24h', // or '12h'
})

Format: HH:mm:ss


Boolean Field

Boolean

Checkbox for true/false values.

is_active: Field.boolean({ 
  label: 'Active',
  defaultValue: true,
})

is_completed: Field.boolean({ 
  label: 'Completed',
  defaultValue: false,
})

Display: Checkbox or toggle switch


Selection Fields

Select

Dropdown with predefined options.

// Simple options (string array)
priority: Field.select({
  label: 'Priority',
  options: ['Low', 'Medium', 'High', 'Critical'],
})

// Advanced options (with values and colors)
status: Field.select({
  label: 'Status',
  options: [
    { label: 'Open', value: 'open', color: '#00AA00', default: true },
    { label: 'In Progress', value: 'in_progress', color: '#FFA500' },
    { label: 'Closed', value: 'closed', color: '#999999' },
  ],
})

// Multi-select
tags: Field.select({
  label: 'Tags',
  multiple: true, // Allow multiple selections
  options: ['Bug', 'Feature', 'Enhancement', 'Documentation'],
})

Configuration:

  • options - Array of string labels or option objects
  • multiple - Allow multiple selections (stores as array)
  • color - Color for badges and charts

Relational Fields

Lookup

Reference to another object (many-to-one).

// Basic lookup
account: Field.lookup('account', { 
  label: 'Account',
  required: true,
})

// Filtered lookup
contact: Field.lookup('contact', { 
  label: 'Contact',
  referenceFilters: ['account_id = $parent.account_id'], // Filter by parent
})

// Multiple lookup
related_cases: Field.lookup('case', { 
  label: 'Related Cases',
  multiple: true, // Many-to-many
})

Configuration:

  • reference - Target object name (snake_case)
  • referenceFilters - Filter criteria for lookup dialog
  • deleteBehavior - 'set_null', 'cascade', or 'restrict'
  • multiple - Allow multiple references

Master-Detail

Parent-child relationship with cascade delete.

account: Field.masterDetail('account', { 
  label: 'Account',
  required: true,
  deleteBehavior: 'cascade', // Delete children when parent deleted
  writeRequiresMasterRead: true, // Security enforcement
})

ℹ️ Info:
Master-Detail vs Lookup:

  • Master-Detail: Tight coupling, cascade deletes, child inherits security
  • Lookup: Loose coupling, set null on delete, independent security

Media Fields

Image

Image upload with preview.

product_image: Field.image({ 
  label: 'Product Image',
  multiple: false,
  maxFileSize: 5 * 1024 * 1024, // 5MB
  acceptedFormats: ['image/jpeg', 'image/png', 'image/webp'],
})

// Multiple images
gallery: Field.image({ 
  label: 'Gallery',
  multiple: true,
  maxFiles: 10,
})

File

File upload field for any file type.

attachment: Field.file({ 
  label: 'Attachment',
  maxFileSize: 25 * 1024 * 1024, // 25MB
  acceptedFormats: ['application/pdf', 'application/msword'],
})

Avatar

Profile picture/avatar upload.

profile_picture: Field.avatar({ 
  label: 'Profile Picture',
  maxFileSize: 2 * 1024 * 1024, // 2MB
  cropAspectRatio: 1, // Square crop
})

Calculated Fields

Formula

Calculated field based on expression.

full_name: Field.formula({ 
  label: 'Full Name',
  expression: 'CONCAT(first_name, " ", last_name)',
  readonly: true,
})

full_address: Field.formula({ 
  label: 'Full Address',
  expression: 'CONCAT(street, ", ", city, ", ", state, " ", postal_code)',
})

days_open: Field.formula({ 
  label: 'Days Open',
  expression: 'DAYS_BETWEEN(created_at, NOW())',
  type: 'number',
})

ℹ️ Info:
Formula fields are automatically calculated and readonly. See Formula Functions for available functions.


Summary (Rollup)

Aggregate data from related records.

total_opportunities: Field.summary({ 
  label: 'Total Opportunities',
  summaryOperations: {
    object: 'opportunity',
    field: 'amount',
    function: 'sum',
  },
})

open_cases_count: Field.summary({ 
  label: 'Open Cases',
  summaryOperations: {
    object: 'case',
    field: 'id',
    function: 'count',
  },
})

Available Functions:

  • count - Count related records
  • sum - Sum numeric field
  • avg - Average numeric field
  • min - Minimum value
  • max - Maximum value

Autonumber

Auto-incrementing unique identifier.

account_number: Field.autonumber({ 
  label: 'Account Number',
  format: 'ACC-{0000}', // ACC-0001, ACC-0002, etc.
})

case_id: Field.autonumber({ 
  label: 'Case ID',
  format: 'CASE-{YYYY}-{00000}', // CASE-2024-00001
})

Format Tokens:

  • {0000} - Zero-padded number
  • {YYYY} - Year
  • {MM} - Month
  • {DD} - Day

Enhanced Field Types

Location

GPS coordinates with map display.

coordinates: Field.location({ 
  label: 'Location',
  displayMap: true,
  allowGeocoding: true, // Convert address to coordinates
})

Note: geolocation is an alternative name for the location field type. Both refer to the same GPS coordinate field.

Data Structure:

{
  latitude: 37.7749,
  longitude: -122.4194,
  altitude: 100, // Optional
  accuracy: 10,  // Optional (meters)
}

Address

Structured address field.

billing_address: Field.address({ 
  label: 'Billing Address',
  addressFormat: 'us', // 'us', 'uk', or 'international'
})

Data Structure:

{
  street: '123 Main St',
  city: 'San Francisco',
  state: 'CA',
  postalCode: '94105',
  country: 'United States',
  countryCode: 'US',
  formatted: '123 Main St, San Francisco, CA 94105',
}

Code

Code editor with syntax highlighting.

code_snippet: Field.code('javascript', {
  label: 'Code Snippet',
  lineNumbers: true,
  theme: 'monokai',
})

sql_query: Field.code('sql', {
  label: 'SQL Query',
  readonly: false,
})

Supported Languages:

  • javascript, typescript, python, java, sql, html, css, json, yaml, markdown, and more

Color

Color picker with multiple formats.

category_color: Field.color({ 
  label: 'Category Color',
  colorFormat: 'hex', // 'hex', 'rgb', 'rgba', 'hsl'
  presetColors: ['#FF0000', '#00FF00', '#0000FF', '#FFFF00'],
  allowAlpha: false,
})

theme_color: Field.color({ 
  label: 'Theme Color',
  colorFormat: 'rgba',
  allowAlpha: true, // Support transparency
})

Rating

Star rating field.

priority: Field.rating(3, { 
  label: 'Priority',
  description: '1-3 stars',
})

satisfaction: Field.rating(5, { 
  label: 'Customer Satisfaction',
  allowHalf: true, // Allow 0.5 increments
})

Configuration:

  • First parameter: maxRating (default: 5)
  • allowHalf - Allow half-star ratings (e.g., 3.5)

Signature

Digital signature capture.

customer_signature: Field.signature({ 
  label: 'Customer Signature',
  required: true,
  readonly: false,
})

Stored as: Base64-encoded image data


Slider

Numeric slider for visual value selection.

volume: Field.slider({ 
  label: 'Volume Level',
  min: 0,
  max: 100,
  step: 1,
  defaultValue: 50,
})

price_range: Field.slider({ 
  label: 'Price Range',
  min: 0,
  max: 10000,
  step: 100,
  marks: { 0: '$0', 5000: '$5K', 10000: '$10K' },
})

Configuration:

  • min - Minimum value
  • max - Maximum value
  • step - Increment step size
  • marks - Optional labeled markers on the slider

QR Code

QR code / Barcode field for scanning and generation.

product_barcode: Field.qrcode({ 
  label: 'Product Barcode',
  format: 'qr', // 'qr', 'barcode', 'ean13', 'code128'
  readonly: false,
})

ticket_code: Field.qrcode({ 
  label: 'Event Ticket',
  format: 'qr',
  autoGenerate: true, // Generate on record creation
})

Supported Formats:

  • qr - QR Code (2D matrix barcode, best for URLs, text, and complex data)
  • barcode - Standard 1D barcode (linear format for simple numeric/text data)
  • ean13 - EAN-13 barcode (13-digit product identifier, commonly used in retail)
  • code128 - Code 128 barcode (high-density 1D format supporting full ASCII character set)

Use Cases:

  • Product SKUs and inventory management (ean13, code128)
  • Event tickets and access control (qr)
  • Document tracking and verification (qr)
  • Shipping labels and logistics (code128)

Field Configuration Reference

Common Properties

All fields support these common properties:

{
  // Identity
  name: 'field_name',        // snake_case machine name
  label: 'Field Label',       // Human-readable label
  description: 'Help text',   // Tooltip/help text
  
  // Constraints
  required: false,            // Is mandatory
  unique: false,              // Enforce uniqueness
  defaultValue: null,         // Default value
  
  // UI Behavior
  hidden: false,              // Hide from default UI
  readonly: false,            // Read-only in UI
  searchable: false,          // Enable search indexing
  
  // Database
  index: false,               // Create database index
  externalId: false,          // Use for upsert operations
  encryption: false,          // Encrypt at rest
}

Best Practices

Naming Conventions

// ✅ GOOD: snake_case for field names
account_name: Field.text({ label: 'Account Name' })
annual_revenue: Field.currency({ label: 'Annual Revenue' })

// ❌ BAD: camelCase or PascalCase
accountName: Field.text({ label: 'Account Name' })
AnnualRevenue: Field.currency({ label: 'Annual Revenue' })

Required Fields

// ✅ GOOD: Require essential fields
name: Field.text({ 
  label: 'Name', 
  required: true,
  maxLength: 255,
})

// ✅ GOOD: Optional fields for flexibility
middle_name: Field.text({ 
  label: 'Middle Name',
  required: false,
})

Searchable Fields

// ✅ GOOD: Make key fields searchable
account_name: Field.text({ 
  searchable: true,
  label: 'Account Name',
})

// ❌ BAD: Don't index large text fields
description: Field.textarea({ 
  searchable: true, // Can impact performance
})

Default Values

// ✅ GOOD: Use meaningful defaults
status: Field.select({
  options: [
    { label: 'Open', value: 'open', default: true },
    { label: 'Closed', value: 'closed' },
  ],
})

created_at: Field.datetime({ 
  defaultValue: 'now',
  readonly: true,
})

Examples from CRM

See the CRM Example for real-world usage of all field types:

  • Account: Autonumber, formula, currency, select with colors
  • Contact: Master-detail, formula (full_name), avatar, email, phone
  • Opportunity: Workflow automation, state machine, percent, datetime
  • Case: Rating (satisfaction), SLA tracking, formula calculations
  • Task: Code, color, rating, location, signature

Next Steps