sercrod

*switch

Summary

*switch selects one branch from its direct children based on an expression, then renders that branch and optionally falls through to later branches until a break is reached. It behaves like a JavaScript switch statement with fallthrough, but is expressed as HTML attributes on a single container element.

Key points:

Aliases:

Basic example

A simple status switch:

<serc-rod id="app" data='{"status":"ready"}'>
  <div *switch="status">
    <p *case="'idle'">Waiting…</p>
    <p *case="'ready'">Ready</p>
    <p *case="'running'">Running</p>
    <p *default>Unknown status</p>
  </div>
</serc-rod>

Behavior:

Behavior

*switch is a structural directive applied to a single container element.

On each render:

Branch selection and fallthrough:

Important structural details:

Case expressions

Each *case / n-case / *case.break / n-case.break attribute holds an expression used to test against the evaluated switch value.

Expression evaluation:

Common patterns:

Evaluation timing

*switch participates in Sercrod’s structural evaluation in this order:

Execution model

Conceptually, the runtime performs these steps for *switch:

  1. Evaluate switch expression

    • Read *switch or n-switch from the host element.
    • Evaluate the expression with the current effective scope to obtain switchVal.
  2. Prepare child scope

    • Construct childScope as a shallow copy of the host scope extended with $switch: switchVal.
    • This scope is used both for case-expression evaluation and for rendering branch bodies.
  3. Scan direct children

    • Collect direct child nodes of the host into an array.
    • Iterate over them in DOM order.
    • Ignore any node that is not an element.
    • For each element, determine whether it is:
      • A default branch (*default / n-default).
      • A case branch (*case, n-case, *case.break, n-case.break).
      • Or not part of the switch at all (no case/default attributes).
  4. Select entry branch

    • While no branch has been selected (falling === false):

      • If the child is a default branch and no earlier case has matched, start fallthrough from this default.
      • Otherwise, if it has a case expression:
        • Evaluate the case expression using _matchCase with $switch.
        • If it matches, set falling = true.
        • If not, skip this child and continue scanning.
  5. Render fallthrough

    • Once falling becomes true:

      • Clone the case/default child (cloneNode(true)).
      • Strip the control attributes from the clone:
        • *case, n-case, *default, n-default, *case.break, n-case.break, *break, n-break.
      • Call _renderElement on the clone with childScope and the parent of the original switch host.
        • The clone’s descendants are rendered normally.
  6. Break handling

    • After rendering each branch child, Sercrod checks the original child element for break markers:

      • If it has any of *break, n-break, *case.break, n-case.break, Sercrod stops the scan and does not consider any later branches.
      • The value of the *break attribute is not evaluated by the *switch implementation; it is treated as a simple presence marker in this context.
  7. Host element

    • The original *switch node itself is not appended to the output DOM.
    • Only the rendered clones of case/default children appear in the final tree.

Variable creation and scope layering

*switch does not introduce new data variables by itself, but it adds a special helper:

Scope behavior:

Parent access

*switch runs within the normal Sercrod scope chain:

Inside case/default branches:

Use with conditionals and loops

*switch composes with other control-flow directives, but you need to be aware of where each directive is placed.

Host-level conditionals:

Example:

<div *if="mode === 'simple'" *switch="status">
  <p *case="'ready'">Simple / Ready</p>
  <p *case="'running'">Simple / Running</p>
  <p *default>Simple / Unknown</p>
</div>
<div *elseif="mode === 'advanced'" *switch="status">
  <p *case="'ready'">Advanced / Ready</p>
  <p *default>Advanced / Other</p>
</div>
<div *else>
  <p>No switch here</p>
</div>

Branches containing loops:

Loops containing switches:

Use with templates, *include and *import

*switch is itself a structural directive that controls which children are rendered and how they are cloned. On the same host element, Sercrod processes *switch before other structural directives like *each, *for, *template, *include, and any helpers built on top of them (such as *import).

Structural restriction on the host element:

Recommended pattern:

What is allowed:

Best practices

Additional examples

Multiple fallthrough branches:

<serc-rod id="app" data='{"level":"warning"}'>
  <div *switch="level">
    <p *case="'info'">Info: low priority.</p>
    <p *case="'warning'">Warning: check this.</p>
    <p *case.break="'error'">Error: action required.</p>
    <p *default>Fallback message.</p>
  </div>
</serc-rod>

Simple default-only switch:

<div *switch="status">
  <p *case="'ready'">Ready</p>
  <p *default>Not ready yet</p>
</div>

Using $switch inside the branch body:

<div *switch="status">
  <p *case="'error'">
    Status is <strong *print="$switch"></strong>.
  </p>
  <p *default>Everything looks fine.</p>
</div>

Notes