sercrod

*case.break

Summary

*case.break is a variant of *case used inside *switch or n-switch. It behaves like *case when matching against the switch value, and in addition it stops evaluating all later *case and *default branches in the same *switch block. It is effectively syntactic sugar for *case="expr" *break on the same element.

Alias:

Both names share the same behavior.

Basic example

A simple status switch that does not fall through past the matching branch:

<serc-rod id="app" data='{"status": "ready"}'>
  <div *switch="$data.status">
    <p *case="'pending'">Pending...</p>
    <p *case.break="'ready'">Ready</p>
    <p *default>Unknown status</p>
  </div>
</serc-rod>

Behavior:

Behavior

*case.break participates only as a child of a *switch or n-switch host:

Within a *switch block:

Conceptually:

Evaluation timing

Within the host element that has *switch or n-switch:

  1. Sercrod evaluates the switch expression once:

    • It reads the attribute value from *switch or n-switch.
    • It evaluates that expression and stores the result as the switch value.
    • The value is then exposed to children as $switch.
  2. Sercrod iterates over child elements in DOM order.

  3. For each child:

    • If it does not have *case, n-case, *case.break, n-case.break, *default, or n-default, it is ignored by the switch logic and never rendered by this *switch.
    • If no branch has started yet:
      • *case / n-case / *case.break / n-case.break:
        • Sercrod evaluates the case expression and compares it to the switch value.
        • If it matches, rendering starts from this branch.
      • *default / n-default:
        • If no earlier branch has matched, rendering starts from this default.
  4. Once a starting branch is chosen (including *case.break):

    • Sercrod clones that branch, removes control attributes, and renders it with the augmented child scope (including $switch).
    • It then continues in fallthrough mode (see below) unless a break is detected.

Case expression semantics

The expression given to *case.break is interpreted in the same way as for *case.

Given:

Sercrod applies the following rules:

  1. It first tries to evaluate the case expression as a normal Sercrod expression, with $switch injected into the scope:

    • If the result is a function, Sercrod calls fn(switchVal, scope) and uses the truthiness of the return value.
    • If the result is a RegExp, Sercrod tests it against String(switchVal).
    • If the result is an array, Sercrod checks whether any element is strictly equal to switchVal (using Object.is semantics).
    • If the result is an object with a has method (for example a Set), Sercrod calls set.has(switchVal) and uses the result.
    • If the result is a boolean, the boolean itself decides the match.
    • If the result is a string, number, or bigint, Sercrod compares it to switchVal using strict identity.
    • For other result types, this step does not produce a match.
  2. If evaluation throws, or if you intentionally keep the expression as a simple string, Sercrod falls back to a token list:

    • It splits the raw string on commas or pipes: "a|b,c" becomes tokens like "a", "b", "c".
    • It trims empty tokens.
    • For each token t:
      • It tries to evaluate t as an expression.
      • If that fails, it uses t itself as a string literal.
      • It compares the result to switchVal using strict identity.
    • If any token matches, the case matches.

Useful patterns:

Scope and $switch

Inside a *switch block, and inside a *case.break branch:

You can freely refer to $switch inside the branch body:

<div *switch="status">
  <p *case.break="'error'">
    Error: <span *print="$switch"></span>
  </p>
  <p *default>OK</p>
</div>

Relationship to *case, *default and *break

Within a *switch block:

Syntactic equivalence:

Sercrod implementation treats both forms in the same way:

Fallthrough and break behavior

*switch in Sercrod uses a DOM-ordered, fallthrough model similar to JavaScript:

*case.break is therefore the most concise way to express:

Example showing fallthrough vs break:

<div *switch="state">
  <p *case="'warm'">Warm</p>
  <p *case="'hot'">Hot</p>
  <p *default>Default</p>
</div>

<div *switch="state">
  <p *case="'warm'">Warm</p>
  <p *case.break="'hot'">Hot only</p>
  <p *default>Default</p>
</div>

Best practices

Additional examples

Simple status mapping with no fallthrough:

<serc-rod id="status-app" data='{"status":"error"}'>
  <div *switch="$data.status">
    <p *case="'ok'">All good</p>
    <p *case.break="'error'">Something went wrong</p>
    <p *default>Unknown status: <span *print="$switch"></span></p>
  </div>
</serc-rod>

Using a function as a case expression:

<serc-rod id="range-switch" data='{"value": 42}'>
  <div *switch="$data.value">
    <p *case="(v) => v < 0">Negative</p>
    <p *case="(v) => v === 0">Zero</p>
    <p *case.break="(v) => v > 0">Positive (and stop)</p>
    <p *default>Unreachable default</p>
  </div>
</serc-rod>

Membership via list syntax:

<serc-rod id="role-switch" data='{"role":"admin"}'>
  <div *switch="$data.role">
    <p *case="'guest' | 'anonymous'">Guest mode</p>
    <p *case.break="'user' | 'admin'">Signed-in user</p>
    <p *default>Other role: <span *print="$switch"></span></p>
  </div>
</serc-rod>

Notes