> ## Documentation Index
> Fetch the complete documentation index at: https://crystalflow.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Conditional Logic

> Build workflows with branching and conditional execution

This example demonstrates building workflows with conditional logic using CrystalFlow's built-in `IfNode` and `SwitchNode`.

## Overview

Conditional workflows enable:

1. **Branch execution** based on runtime conditions
2. **Skip nodes** when conditions aren't met
3. **Dynamic path selection** based on values
4. **Multi-way routing** with switch/case logic

## Basic If/Else Flow

The `IfNode` provides classic if/else conditional branching:

```typescript theme={null}
import { Workflow, IfNode, BooleanInputNode, DisplayNode } from '@crystalflow/core';

const workflow = new Workflow('if-else-example');

// Input: true/false
const boolInput = workflow.addNode(BooleanInputNode, {
  position: { x: 100, y: 200 }
});

// If node: routes based on condition
const ifNode = workflow.addNode(IfNode, {
  position: { x: 300, y: 200 }
});

// Then branch
const thenDisplay = workflow.addNode(DisplayNode, {
  position: { x: 500, y: 100 }
});

// Else branch
const elseDisplay = workflow.addNode(DisplayNode, {
  position: { x: 500, y: 300 }
});

// Connect
workflow.connect(boolInput.id, 'value', ifNode.id, 'condition');
workflow.connect(boolInput.id, 'value', ifNode.id, 'value'); // Pass data through
workflow.connect(ifNode.id, 'thenOutput', thenDisplay.id, 'message');
workflow.connect(ifNode.id, 'elseOutput', elseDisplay.id, 'message');

// Execute
const result = await workflow.execute();
// If condition = true: thenDisplay shows "true"
// If condition = false: elseDisplay shows "false"
```

### How It Works

1. `BooleanInputNode` provides the condition value (true/false)
2. `IfNode` receives the condition and optional data
3. Based on condition:
   * `true` → Routes to `thenOutput`
   * `false` → Routes to `elseOutput`
4. Only the active branch executes - the other is skipped

<Tip>
  Only nodes connected to the active output execute. If condition is true,
  nodes on the else branch never run!
</Tip>

## Numeric Comparison

Use comparison nodes to generate boolean conditions:

```typescript theme={null}
import { NumberInputNode, CompareNode, IfNode, DisplayNode } from '@crystalflow/core';

const workflow = new Workflow('comparison-example');

// Input number
const numberInput = workflow.addNode(NumberInputNode);

// Compare: number > 10?
const compareNode = workflow.addNode(CompareNode);
compareNode.setProperty('operator', '>');
compareNode.setProperty('b', 10);

// If node
const ifNode = workflow.addNode(IfNode);

// Results
const highDisplay = workflow.addNode(DisplayNode, {
  data: { prefix: 'High: ' }
});

const lowDisplay = workflow.addNode(DisplayNode, {
  data: { prefix: 'Low: ' }
});

// Connect
workflow.connect(numberInput.id, 'value', compareNode.id, 'a');
workflow.connect(compareNode.id, 'result', ifNode.id, 'condition');
workflow.connect(numberInput.id, 'value', ifNode.id, 'value');
workflow.connect(ifNode.id, 'thenOutput', highDisplay.id, 'message');
workflow.connect(ifNode.id, 'elseOutput', lowDisplay.id, 'message');

// Execute with value = 15
// Result: "High: 15" (because 15 > 10)
```

### Available Comparison Operators

* `>` - Greater than
* `>=` - Greater than or equal
* `<` - Less than
* `<=` - Less than or equal
* `==` - Equal
* `!=` - Not equal

## Switch/Case Routing

The `SwitchNode` provides multi-way branching:

```typescript theme={null}
import { Workflow, SwitchNode, StringInputNode, DisplayNode } from '@crystalflow/core';

const workflow = new Workflow('switch-example');

// Input: status value
const statusInput = workflow.addNode(StringInputNode);

// Switch: route by status
const switchNode = workflow.addNode(SwitchNode);
switchNode.setProperty('cases', ['pending', 'approved', 'rejected']);

// Handlers for each case
const pendingHandler = workflow.addNode(DisplayNode, {
  data: { prefix: 'Pending: ' }
});

const approvedHandler = workflow.addNode(DisplayNode, {
  data: { prefix: 'Approved: ' }
});

const rejectedHandler = workflow.addNode(DisplayNode, {
  data: { prefix: 'Rejected: ' }
});

const defaultHandler = workflow.addNode(DisplayNode, {
  data: { prefix: 'Unknown: ' }
});

// Connect
workflow.connect(statusInput.id, 'value', switchNode.id, 'value');
workflow.connect(statusInput.id, 'value', switchNode.id, 'data');
workflow.connect(switchNode.id, 'case_0', pendingHandler.id, 'message');   // 'pending'
workflow.connect(switchNode.id, 'case_1', approvedHandler.id, 'message');  // 'approved'
workflow.connect(switchNode.id, 'case_2', rejectedHandler.id, 'message');  // 'rejected'
workflow.connect(switchNode.id, 'default', defaultHandler.id, 'message');

// Execute with value = 'approved'
// Result: "Approved: approved" (only approvedHandler runs)
```

### Dynamic Outputs

`SwitchNode` generates outputs dynamically based on the `cases` property:

* 3 cases → 4 outputs: `case_0`, `case_1`, `case_2`, `default`
* Add case → new output appears automatically
* Remove case → output disappears

```typescript theme={null}
// Configure cases in property panel
switchNode.setProperty('cases', ['apple', 'banana', 'orange', 'grape']);

// Generates outputs:
// - case_0 (apple)
// - case_1 (banana)  
// - case_2 (orange)
// - case_3 (grape)
// - default
```

## Nested Conditionals

Conditional nodes can be nested for complex decision trees:

### If Inside If

```typescript theme={null}
const workflow = new Workflow('nested-if-example');

// Check if positive
const outerIf = workflow.addNode(IfNode);
outerIf.name = 'CheckPositive';

// Check if even (inside then branch)
const innerIf = workflow.addNode(IfNode);
innerIf.name = 'CheckEven';

// Handlers
const positiveEvenHandler = workflow.addNode(DisplayNode);
const positiveOddHandler = workflow.addNode(DisplayNode);
const negativeHandler = workflow.addNode(DisplayNode);

// Connect outer if
workflow.connect(numberInput.id, 'value', outerIf.id, 'condition'); // isPositive?
workflow.connect(outerIf.id, 'thenOutput', innerIf.id, 'condition'); // isEven?
workflow.connect(outerIf.id, 'elseOutput', negativeHandler.id, 'message');

// Connect inner if
workflow.connect(innerIf.id, 'thenOutput', positiveEvenHandler.id, 'message');
workflow.connect(innerIf.id, 'elseOutput', positiveOddHandler.id, 'message');

// Execution paths:
// number > 0 AND even → positiveEvenHandler
// number > 0 AND odd → positiveOddHandler  
// number <= 0 → negativeHandler
```

### Switch Inside If

```typescript theme={null}
const workflow = new Workflow('switch-in-if-example');

// Authentication check
const authCheck = workflow.addNode(IfNode);
authCheck.name = 'CheckAuthenticated';

// Role routing (inside then branch)
const roleSwitch = workflow.addNode(SwitchNode);
roleSwitch.setProperty('cases', ['admin', 'user', 'guest']);

// Handlers
const adminHandler = workflow.addNode(DisplayNode);
const userHandler = workflow.addNode(DisplayNode);
const guestHandler = workflow.addNode(DisplayNode);
const loginHandler = workflow.addNode(DisplayNode);

// Connect
workflow.connect(authCheck.id, 'thenOutput', roleSwitch.id, 'value');
workflow.connect(authCheck.id, 'elseOutput', loginHandler.id, 'message');
workflow.connect(roleSwitch.id, 'case_0', adminHandler.id, 'message');
workflow.connect(roleSwitch.id, 'case_1', userHandler.id, 'message');
workflow.connect(roleSwitch.id, 'case_2', guestHandler.id, 'message');

// Execution:
// authenticated + role='admin' → adminHandler
// authenticated + role='user' → userHandler
// not authenticated → loginHandler
```

## Advanced Patterns

### Multi-Stage Validation

Validate data through multiple conditional checks:

```typescript theme={null}
const workflow = new Workflow('validation-workflow');

// Stage 1: Check if value exists
const checkExists = workflow.addNode(IfNode);

// Stage 2: Check if value is valid type
const checkType = workflow.addNode(IfNode);

// Stage 3: Check if value in range
const checkRange = workflow.addNode(IfNode);

// Handlers
const successHandler = workflow.addNode(DisplayNode);
const missingHandler = workflow.addNode(DisplayNode);
const invalidTypeHandler = workflow.addNode(DisplayNode);
const outOfRangeHandler = workflow.addNode(DisplayNode);

// Connect: exists? → validType? → inRange? → success
workflow.connect(checkExists.id, 'thenOutput', checkType.id, 'condition');
workflow.connect(checkExists.id, 'elseOutput', missingHandler.id, 'message');
workflow.connect(checkType.id, 'thenOutput', checkRange.id, 'condition');
workflow.connect(checkType.id, 'elseOutput', invalidTypeHandler.id, 'message');
workflow.connect(checkRange.id, 'thenOutput', successHandler.id, 'message');
workflow.connect(checkRange.id, 'elseOutput', outOfRangeHandler.id, 'message');
```

### State Machine

Implement state transitions with switch:

```typescript theme={null}
const workflow = new Workflow('state-machine');

const currentState = workflow.addNode(StringInputNode);
const eventInput = workflow.addNode(StringInputNode);

const stateSwitch = workflow.addNode(SwitchNode);
stateSwitch.setProperty('cases', ['idle', 'loading', 'success', 'error']);

// State handlers
const idleHandler = workflow.addNode(ProcessIdleNode);
const loadingHandler = workflow.addNode(ProcessLoadingNode);
const successHandler = workflow.addNode(ProcessSuccessNode);
const errorHandler = workflow.addNode(ProcessErrorNode);

workflow.connect(currentState.id, 'value', stateSwitch.id, 'value');
workflow.connect(eventInput.id, 'value', stateSwitch.id, 'data');
workflow.connect(stateSwitch.id, 'case_0', idleHandler.id, 'event');
workflow.connect(stateSwitch.id, 'case_1', loadingHandler.id, 'event');
workflow.connect(stateSwitch.id, 'case_2', successHandler.id, 'event');
workflow.connect(stateSwitch.id, 'case_3', errorHandler.id, 'event');

// Each handler can transition to new state and emit events
```

## React Component Example

```tsx theme={null}
import React from 'react';
import { WorkflowBuilder } from '@crystalflow/react';
import {
  IfNode,
  SwitchNode,
  BooleanInputNode,
  NumberInputNode,
  StringInputNode,
  CompareNode,
  DisplayNode
} from '@crystalflow/core';

function ConditionalWorkflowExample() {
  const nodes = [
    // Flow Control
    IfNode,
    SwitchNode,
    
    // Input nodes
    BooleanInputNode,
    NumberInputNode,
    StringInputNode,
    
    // Logic nodes
    CompareNode,
    
    // Output
    DisplayNode
  ];

  const handleExecute = (result) => {
    console.log('Workflow executed:', result);
  };

  return (
    <div className="conditional-workflow-example">
      <h1>Conditional Logic Workflow</h1>
      <p>
        Drag IfNode and SwitchNode from the Flow Control category to create
        branching workflows.
      </p>
      
      <WorkflowBuilder
        nodes={nodes}
        onExecute={handleExecute}
        showNodePalette={true}
        showPropertyPanel={true}
        style={{ height: '600px' }}
      />
      
      <div className="instructions">
        <h3>Try These Workflows:</h3>
        <ol>
          <li><strong>Simple If/Else:</strong> BooleanInput → If → Display (then/else)</li>
          <li><strong>Comparison:</strong> NumberInput → Compare → If → Display</li>
          <li><strong>Switch Routing:</strong> StringInput → Switch (3 cases) → Multiple Displays</li>
          <li><strong>Nested:</strong> If → If (nested in then branch)</li>
        </ol>
      </div>
    </div>
  );
}

export default ConditionalWorkflowExample;
```

## Try It Yourself

The CrystalFlow examples package includes a complete `ConditionalNodesDemo.tsx` with:

* All logic test nodes (CompareNode, IsPositiveNode, IsEvenNode, etc.)
* IfNode and SwitchNode from @crystalflow/core
* 7 documented workflow scenarios
* Full interactive UI with property panel for configuring cases

**Run the examples:**

```bash theme={null}
cd packages/examples
npm run dev
# Navigate to the Conditional Flow demo
```

## Key Concepts

<CardGroup cols={2}>
  <Card title="Branch Evaluation">
    `evaluateCondition()` determines which branch executes at runtime
  </Card>

  <Card title="Single Branch Execution">
    Only the active branch runs - others are completely skipped
  </Card>

  <Card title="Dynamic Outputs">
    SwitchNode outputs update automatically when cases change
  </Card>

  <Card title="Nested Conditionals">
    Conditionals can be nested arbitrarily deep for complex logic
  </Card>
</CardGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Conditional Flow Guide" href="/advanced/conditional-flow">
    Deep dive into conditional flow architecture
  </Card>

  <Card title="Built-in Nodes API" href="/api-reference/core/builtin-nodes">
    Complete IfNode and SwitchNode API reference
  </Card>

  <Card title="Creating Custom Nodes" href="/guides/creating-custom-nodes">
    Build your own conditional nodes
  </Card>

  <Card title="Data Processing" href="/examples/data-processing">
    More workflow examples
  </Card>
</CardGroup>
