Skip to content

Latest commit

 

History

History
155 lines (120 loc) · 5.47 KB

File metadata and controls

155 lines (120 loc) · 5.47 KB
title Select Field
description Dropdown selection field with single or multiple options

import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo';

The Select Field component provides a dropdown for selecting one or more options from a predefined list.

Basic Usage

With Colors

Multiple Selection

Cascading & Role-Gated Options

An option can carry a visibleWhen CEL predicate — it is offered only when the predicate is TRUE. The predicate is evaluated against the live record plus current_user, the same engine and binding environment as a field-level visibleWhen. This single mechanism covers two needs:

  • Cascading / dependent options — narrow a child list by a parent field (country → province → city).
  • Role / context gating — offer an option only to certain users.

Declare the sibling field(s) a select reacts to with dependsOn. While any is empty the control is gated (a "Select country first" hint) instead of showing an unfiltered list; once the parent changes, the list re-evaluates and any now-invalid selection is cleared automatically (no stale "China + California" pair).

Cascading (country → province)

{
  "type": "form",
  "fields": [
    { "name": "country", "label": "Country", "type": "select", "options": [
      { "label": "China", "value": "cn" },
      { "label": "United States", "value": "us" }
    ]},
    { "name": "province", "label": "Province", "type": "select", "dependsOn": "country", "options": [
      { "label": "Zhejiang",   "value": "zj", "visibleWhen": "record.country == 'cn'" },
      { "label": "Guangdong",  "value": "gd", "visibleWhen": "record.country == 'cn'" },
      { "label": "California",  "value": "ca", "visibleWhen": "record.country == 'us'" },
      { "label": "Texas",       "value": "tx", "visibleWhen": "record.country == 'us'" }
    ]}
  ]
}

Chain a third level (city, dependsOn: "province") the same way — the gate and cascade-clear propagate down the chain.

Role-gated option

{ "name": "tier", "type": "select", "options": [
  { "label": "Standard", "value": "standard" },
  { "label": "Admin only", "value": "admin_only", "visibleWhen": "'admin' in current_user.roles" }
]}

Security — hiding is UX, not authorization. A visibleWhen on an option only removes it from the dropdown on the client; a determined caller can still submit the value. When an option is gated for access-control reasons the server must also reject writes of that value (the rule-validator evaluates the picked value's visibleWhen). Use option visibleWhen for convenience and cascades freely; for real authorization, pair it with server-side enforcement.

When to use options vs. a lookup

visibleWhen options are for small, static dictionaries (category → subcategory, a handful of provinces). When the data is large, changes over time, or is shared across forms (real country/province/city tables, org units, product catalogs), model each level as a lookup with depends_on instead — the candidate query is filtered server-side and paginated. See Lookup Field.

Field Schema

interface SelectFieldSchema {
  type: 'select';
  name: string;                  // Field name/ID
  label?: string;                // Field label
  placeholder?: string;          // Placeholder text
  value?: string | string[];     // Default value(s)
  multiple?: boolean;            // Allow multiple selections
  required?: boolean;            // Is field required
  readonly?: boolean;            // Read-only mode
  disabled?: boolean;            // Disabled state
  className?: string;            // Additional CSS classes

  // Options
  options: SelectOption[];       // Available options

  // Cascading: sibling field(s) whose value drives this option list. While any
  // is empty the field is gated ("Select <parent> first"); it re-evaluates as
  // they change. Same knob dependent lookups use.
  dependsOn?: string | string[];
}

interface SelectOption {
  label: string;                 // Display label
  value: string;                 // Option value
  color?: string;                // Badge color (gray, red, blue, etc.)
  disabled?: boolean;            // Disable specific option

  // Per-option visibility predicate (CEL). The option is offered only when TRUE,
  // evaluated against the live record + current_user (same engine/env as a
  // field-level visibleWhen). Omit = always available.
  visibleWhen?: string;
}

Available Colors

  • gray - Default neutral color
  • red - For errors, urgent items
  • orange - For warnings, high priority
  • yellow - For pending, attention needed
  • green - For success, completed
  • blue - For info, in progress
  • indigo - For special items
  • purple - For creative, design
  • pink - For featured items

Cell Renderer

In tables/grids, select values are displayed as colored badges:

import { SelectCellRenderer } from '@object-ui/fields';

// Single value: Colored badge
// Multiple values: Multiple badges in a row

Use Cases

  • Status Fields: Order status, task status
  • Categories: Product categories, content types
  • Tags: Multi-tag selection
  • Priorities: Task or ticket priorities
  • Roles: User roles or permissions