*break
Summary
*break is a control directive used inside *switch blocks. It stops the *switch fallthrough after the current branch has been rendered. The alias n-break behaves the same.
In addition, *case.break is a shorthand that combines *case and *break on a single element:
*case.break="expr"is equivalent to*case="expr" *break.
Basic example
A typical *switch with a breaking case:
<serc-rod id="app" data='{"status":"ready"}'>
<div *switch="status">
<p *case="'idle'">Idle…</p>
<!-- Match "ready" and then stop evaluating later branches -->
<p *case.break="'ready'">Ready</p>
<!-- Never rendered, because the previous branch breaks -->
<p *case="'ready'">Also ready (not reached)</p>
<!-- Never reached in this example -->
<p *default>Unknown status</p>
</div>
</serc-rod>
Conceptually:
*case.break="'ready'"matches whenstatus === "ready".- That branch is rendered.
- Because it is a breaking branch, the
*switchstops and later siblings are not evaluated or rendered.
Behavior
*break and *case.break are interpreted only in the context of *switch:
-
Location:
- Only direct child elements of a
*switchhost are considered. - Text nodes and non-element nodes are ignored.
- Only direct child elements of a
-
Branch types:
*caseorn-casedefine a normal case.*case.breakorn-case.breakdefine a case that also breaks after rendering.*defaultorn-defaultdefine the fallback branch if no case matched.
-
Breaking rules:
- If a branch element has
*breakorn-break, the*switchstops after rendering that branch. - If a branch element uses
*case.breakorn-case.break, the*switchstops after rendering that branch. - Later siblings in the
*switchbody are not evaluated or rendered.
- If a branch element has
Important limitations:
*breakdoes not evaluate its attribute value in*switchblocks.*break="expr"is treated the same as*breakwithout a value.
- As of the current implementation,
*breakdoes not stop*foror*eachloops.- The internal short text may mention loops, but loop control is not wired to
*break. - Placing
*breakinside a*foror*eachbody has no special effect on those loops.
- The internal short text may mention loops, but loop control is not wired to
Aliases:
*breakandn-breakare equivalent.*case.breakandn-case.breakare equivalent.
Evaluation timing
*break participates in the evaluation of *switch as follows:
-
The
*switchhost evaluates its expression once and stores the result in$switchfor children. -
Sercrod walks the direct child elements of the
*switchhost from top to bottom. -
It decides when to start "falling through" (rendering) by matching
*caseand*case.breakagainst$switch, or by reaching*default. -
Once falling has started:
- Each child element in the fallthrough range is rendered in order.
- After rendering each such branch, Sercrod checks the original branch element for:
*breakorn-break*case.breakorn-case.break
- If any of those are present, the walk stops and no further children of the
*switchare processed.
Notes:
- The check for
*breakand*case.breakhappens after rendering the branch, but it is based on the original element’s attributes. - The clone used for rendering has control attributes removed so they do not leak into the final HTML.
Execution model
Conceptually, for a *switch host:
-
Evaluate the
*switchexpression and store it as$switchfor children. -
Collect the direct child elements.
-
Iterate over those children in DOM order.
- Determine whether each child is:
- A
*caseorn-casebranch. - A
*case.breakorn-case.breakbranch. - A
*defaultorn-defaultbranch. - Something else (ignored by the switch controller).
- A
- Determine whether each child is:
-
Until the first matching branch is found, nothing is rendered.
-
Once a matching branch (or
*default) is found, enter "fallthrough" mode:- For each branch in fallthrough mode:
- Clone the original node.
- Strip control attributes (
*case,*default,*case.break,*break, and theirn-aliases). - Render the clone with the child scope (which includes
$switch). - Inspect the original node for breaking attributes:
*break,n-break,*case.break, orn-case.break.
- If any breaking attribute is present, stop the loop.
- For each branch in fallthrough mode:
-
Other non-branch child nodes (such as comments or text) are ignored by the switch controller.
There is no separate execution path for *break outside of *switch; other directives do not consult it.
Variable creation
*break does not create any variables:
- It does not introduce new names into the scope.
- It does not affect
$switch,$data,$root, or$parent. - It is purely a structural control flag for
*switch.
Similarly, *case.break uses the same expression as *case:
- The value of
*case.break="expr"is evaluated by the same mechanism that handles*case="expr". - No additional variables are created by using
.break.
Scope layering
In a *switch block:
-
Child branches are evaluated with a scope that merges:
- The parent scope at the point where the
*switchappears. - A
$switchproperty that holds the evaluated value of the*switchexpression.
- The parent scope at the point where the
-
*breakand*case.breakdo not change the scope. -
Using
*breakdoes not affect variable visibility or lifetime; it only shortens which branches are processed.
Parent access
*break does not alter the way parents are accessed:
-
Branch bodies can still access:
- Host data via whatever property names you used in
data. $rootfor the root Sercrod host’s data.$parentfor the nearest ancestor Sercrod host’s data.- Methods injected via
*methodsor configuration.
- Host data via whatever property names you used in
-
*breakdoes not expose any special information about the*switchbeyond what$switchalready provides.
Use with conditionals and loops
Within *switch bodies:
-
You can combine
*breakor*case.breakwith normal conditionals and content:*ifinside the branch body is independent of*break.- Nested
*switchblocks inside the body work as usual; their own*breakonly affects the inner switch.
Example pattern with an inner *if:
<div *switch="status">
<p *case.break="'ready'">
<span *if="$root.showLabel">Ready</span>
</p>
<p *default>Other status</p>
</div>
Interaction with *for and *each:
-
As of the current implementation:
*breakhas no special effect on*foror*eachloops.- Loops do not consult
*breakwhen iterating. - Writing
*break="expr"inside a*foror*eachbody does not stop the loop.
-
If you need to stop rendering items based on a condition, you must express that either by:
- Pre-filtering the collection.
- Using conditionals (
*if) inside the loop body. - Or reorganizing your data so that the loop naturally contains only the items you want to show.
Best practices
-
Prefer
*case.breakfor "match and break":- Use
*case.break="expr"when you want:- The branch to act like a case.
- The switch to stop after that branch.
- Use
-
Use
*breakon a branch only when you need to:- Separate the matching logic from the breaking logic.
- For example, when the decision to break is expressed structurally rather than by choosing
.break.
-
Keep
*breakclose to*case:- Treat
*case="expr" *breakas equivalent to*case.break="expr". - Choose one style per codebase for readability.
- Treat
-
Do not rely on
*breakin loops:- Even though the short text mentions loops, there is no loop control implemented for
*breakat this time. - Express loop cutoffs using data and conditionals instead of
*break.
- Even though the short text mentions loops, there is no loop control implemented for
-
Limit
*breakto child elements of*switch:- Placing
*breakon elements that are not direct children of a*switchhost has no special effect. - In such locations, it behaves as a non-interpreted attribute.
- Placing
Examples
Unconditional break with *break:
<serc-rod id="app" data='{"status":"processing"}'>
<div *switch="status">
<p *case="'processing'" *break>Processing…</p>
<p *case="'processing'">Also processing (not reached)</p>
<p *default>Fallback (not reached)</p>
</div>
</serc-rod>
- The first
*casematches and renders. - Because it also has
*break, the following branches are skipped.
Mixed fallthrough with one breaking branch:
<serc-rod id="app" data='{"status":"multi"}'>
<div *switch="status">
<p *case="'multi'">First line</p>
<p *case="'multi'">Second line</p>
<p *case.break="'multi'">Third line, then break</p>
<p *case="'multi'">Fourth line (not reached)</p>
<p *default>Default (not reached)</p>
</div>
</serc-rod>
- All three
*casebranches for"multi"are rendered in order until the.breakcase. - After the
.breakbranch, the*switchstops and no further siblings are evaluated.
Notes
-
*breakandn-breakare aliases that only have meaning inside*switchchildren. -
*case.breakandn-case.breakare equivalent shorthands for*case + *break. -
The current implementation:
- Removes control attributes (
*case,*default,*case.break,*break, and theirn-aliases) from the clones that are actually rendered, so these do not appear in the final HTML. - Checks for breaking attributes on the original nodes only.
- Does not connect
*breakto*foror*eachloops.
- Removes control attributes (
-
If you need loop-level early termination, use data modeling and conditionals rather than
*break.