sercrod

*if

Summary

*if conditionally renders an element when the expression is truthy. *elseif and *else form a chain with a preceding *if so that exactly one branch is chosen. The chain is defined across sibling elements and is evaluated from left to right.

Aliases:

Only one of the branches in a single chain is rendered; the others are skipped.

Basic example

A simple visible or hidden panel:

<serc-rod id="app" data='{"show": true}'>
  <section *if="show">
    <h2>Panel</h2>
    <p>This panel is visible when show is truthy.</p>
  </section>
</serc-rod>

When show is truthy, the section is rendered. When show becomes falsy, the section is not rendered at all.

Behavior

*if, *elseif, and *else work together as a chain on sibling elements.

Core rules:

For each chain:

  1. Sercrod evaluates the branches from left to right.
  2. The first branch whose condition is truthy is selected.
  3. If no condition is truthy and there is an *else branch, that *else branch is selected.
  4. If no branch is selected (no truthy condition and no *else), nothing is rendered for this chain.

Invalid chains:

Rendering result:

Condition evaluation semantics

The expression on *if or *elseif is evaluated using Sercrod’s expression evaluator with special truthiness rules:

If evaluating the expression throws an error:

Empty expressions:

Evaluation timing

The evaluation order around *if is:

  1. Host-level *let (non structural) is evaluated before structural directives:
    • *let or n-let on the same element can prepare or adjust the scope before *if runs.
  2. The *if / *elseif / *else chain is detected and evaluated on sibling elements.
    • If the current node is not the head of a chain, it delegates to the head.
  3. If no branch is selected, nothing in the chain is rendered and Sercrod returns.
  4. If a branch is selected:
    • The chosen element is cloned.
    • Conditional attributes (*if, n-if, *elseif, n-elseif, *else, n-else) and branch-level *let are removed from the clone.
    • The clone is then rendered as a normal element, so other directives on it (such as *switch, *each, *for, attribute bindings, events, and so on) are applied in the usual order.

Effectively:

Execution model

Conceptually, Sercrod processes *if chains like this:

  1. Starting from a given node, check whether it has any of *if, *elseif, *else, or their n- aliases.
  2. If so, find the head of the chain:
    • If the current node has *if or n-if, it is the head.
    • Otherwise, scan previous siblings to find the nearest *if or n-if, stopping when:
      • A non-conditional element is encountered, or
      • The beginning of the container is reached.
  3. If no *if is found, the current *elseif or *else is treated as an invalid chain and ignored.
  4. Only when processing the head element:
    • Collect the chain by walking right through sibling elements that have *if, *elseif, or *else.
    • Stop when hitting:
      • A non-conditional element, or
      • A new *if or n-if (which starts another chain).
  5. For each collected branch:
    • Start with the effective scope that includes host-level *let.
    • If the branch element has *let or n-let, create a branch scope that prototypes the parent scope and apply that *let into it.
    • For an else branch:
      • If no branch has been chosen yet, mark this branch as a candidate and break evaluation.
    • For an if or elseif branch:
      • Evaluate the condition using the branch scope.
      • If truthy, choose this branch, remember its branch scope, and stop evaluating further branches.
  6. If no branch has been chosen:
    • The entire chain renders nothing and returns.
  7. If a branch has been chosen:
    • Clone the chosen element.
    • Remove all conditional attributes and branch-level *let attributes from the clone.
    • Render the clone with the chosen branch scope.
    • The original chain elements remain only as template nodes.

This model keeps the chain logic compact and ensures exactly one branch (or none) appears in the final DOM.

Variable creation and scope layering

*if by itself does not create new variables. However, it interacts with *let in two ways:

Important points:

Parent access

*if does not introduce any special parent references on its own.

Within a chosen branch:

Branch-level *let can add or override variables on top of these, but does not remove access to parent data.

Use with conditionals and loops

Combining *if with loops and other structural directives is common and supported when they are placed thoughtfully.

Basic patterns:

*if and *switch:

Use with templates, include, and import

*if works naturally with *template, *include, and *import.

Typical combinations:

Restrictions:

Best practices

Additional examples

Toggling content based on numeric thresholds:

<serc-rod id="score-app" data='{"score": 72}'>
  <p *if="score >= 80">Great job!</p>
  <p *elseif="score >= 50">Good effort.</p>
  <p *else>Keep trying.</p>
</serc-rod>

Checking multiple flags:

<serc-rod id="flags" data='{"is_guest": false, "is_admin": true}'>
  <p *if="is_admin">Administrator view</p>
  <p *elseif="is_guest">Guest view</p>
  <p *else>Standard user view</p>
</serc-rod>

Using *if to guard a costly block:

<serc-rod id="lazy" data='{"show_details": false}'>
  <button @click="show_details = !show_details">
    Toggle details
  </button>

  <section *if="show_details">
    <h2>Details</h2>
    <p>Only rendered when needed.</p>
  </section>
</serc-rod>

Notes