obsidian-formfire/docs/plans/2026-02-13-conditional-logic-design.md
tolvitty 22eeccf022 docs: add conditional logic design document
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 20:16:32 +01:00

5.4 KiB
Raw Blame History

Conditional Logic Design Document

Date: 2026-02-13 Status: Approved Plugin: obsidian-formfire Phase: 3 — Conditional Field Visibility

Problem

Forms with many fields become overwhelming when not all fields are relevant in every context. A "Meeting Notes" form shouldn't show "Book Author" fields. Currently all fields are always visible — users must skip irrelevant ones manually.

Solution

Add per-field conditional visibility rules with AND/OR logic. Fields can reference other fields' values to determine whether they should be shown or hidden. Hidden fields are excluded from submission.

Approach

Rule-per-Field — each FormField gets an optional conditions object containing rules and a logic combinator. This keeps conditions co-located with the field they control and avoids a separate rules data structure.

Data Model

New Types

type ConditionOperator =
  | 'equals' | 'not_equals'           // all field types
  | 'contains' | 'not_contains'       // text, textarea, tags
  | 'is_empty' | 'is_not_empty'       // all field types
  | 'greater_than' | 'less_than';     // number, rating, slider

interface ConditionRule {
  fieldId: string;              // reference to another field
  operator: ConditionOperator;
  value?: unknown;              // not needed for is_empty/is_not_empty
}

interface FieldConditions {
  logic: 'and' | 'or';         // how rules are combined
  rules: ConditionRule[];       // at least 1 rule
}

FormField Extension

interface FormField {
  // ... existing fields ...
  conditions?: FieldConditions;  // optional, undefined = always visible
}

Operator Availability by Field Type

Operator text/textarea number toggle date/time dropdown tags note-link/folder rating slider color
equals / not_equals yes yes yes yes yes yes yes yes yes
contains / not_contains yes yes
is_empty / is_not_empty yes yes yes yes yes yes yes yes yes
greater_than / less_than yes yes yes

Note: toggle doesn't support is_empty since it always has a value (true/false).

Evaluation Engine

New module: src/utils/condition-engine.ts

evaluateConditions(
  conditions: FieldConditions,
  values: Record<string, unknown>
): boolean

Logic

  1. Each ConditionRule is evaluated against the current value of the referenced field
  2. Results are combined: and = all must be true, or = at least one must be true
  3. Return: true = show field, false = hide field

Operator Semantics

  • equals / not_equals — string coercion for comparison, strict for booleans
  • contains / not_contains — substring check for strings, element check for arrays (tags)
  • is_empty / is_not_emptynull, undefined, "", [] count as empty
  • greater_than / less_than — numeric comparison (parseFloat)

Cycle Prevention

Fields can only reference fields that appear before them in the field list. This prevents circular dependencies by design and is enforced in the builder UI (field dropdown only shows preceding fields).

Reactivity in Form Modal

  1. Change listeners on every field — value changes trigger reevaluateVisibility()
  2. reevaluateVisibility() iterates all fields with conditions, evaluates them, toggles display: none
  3. Hidden fields excluded from submit — values not written to frontmatter
  4. Validation skips hidden fields — a required field that is hidden does not block submission

Builder UI

Per-Field Conditions Editor

Located below existing field settings, collapsible:

Collapsed: Shows summary like "Show if: type = Meeting" or "Always visible"

Expanded:

  1. Logic dropdown at top: ALL conditions match (AND) / ANY condition matches (OR)
  2. Rule rows, each containing:
    • Field dropdown (only fields before current field)
    • Operator dropdown (filtered by selected field's type)
    • Value input (type-dependent: text input, dropdown with options, number input, toggle; hidden for is_empty/is_not_empty)
    • Delete button (×)
  3. "+ Add condition" button

Live Preview Behavior

Fields with unmet conditions are shown grayed out with a "conditional" badge in the builder preview (not fully hidden, so the builder user can see all fields exist).

Files Changed

File Change
src/types.ts New types: ConditionOperator, ConditionRule, FieldConditions; add conditions? to FormField
src/utils/condition-engine.ts NewevaluateConditions(), operator logic, helpers
src/utils/validators.ts Accept visibility map, skip hidden fields
src/ui/form-modal.ts Change listeners, reevaluateVisibility(), exclude hidden fields from submit
src/ui/form-builder.ts Conditions editor UI per field (collapsed/expanded, rule editor)
src/ui/field-renderers.ts No changes — conditions operate one level above
styles.css Condition editor styles, conditional badge in preview, show/hide transitions

Out of Scope

  • Nested condition groups (AND inside OR) — one level is sufficient
  • Form-level conditions (hide entire form)
  • Actions other than show/hide (e.g. set value, change required)
  • Migration — conditions is optional, existing forms work unchanged