Control flow
Blocks start with #, such as #if and #for, and wrap their body in braces. A block's code ships to the browser only if what it depends on can change there. Otherwise the block is HTML only.
#if
#if (condition) renders its body when the condition is true. #else if and #else follow it:
The sample runs when it comes into view.
#for
#for (item of list) renders its body for each item. #else renders when the list is empty:
The sample runs when it comes into view.
person, indexnames the item and its position. The index is optional.by person.idis the key. When the list changes, items with the same key keep their elements, and only items that changed update.by indexkeys items by their position. Withoutby, each item is its own key, which suits lists of strings and numbers.- The item can be destructured:
#for ({ id, name } of people by id).
Pick a key that stays the same for an item, such as an ID from a database. A key that changes renders the item again.
Windowed lists
A long list can render only the items in view. window(height) after the header gives the height of an item in pixels, and the browser renders the items that come into view as the user scrolls:
<div style="height: 400px; overflow: auto">
<table>
<tbody>
#for (row of rows by row.id) window(32) {
<tr><td>{row.name}</td></tr>
}
</tbody>
</table>
</div>
- The server renders the first items, 20 by default, or the count of
window(height, count). A spacer before the items and one after give the list the height of all of them, so the page has its height before its code loads. - The browser renders the items in view, a few more on each side, as the element that scrolls the list, or the page, scrolls. It measures the items that render, and uses their height for the rest.
- An item that leaves the view keeps its scope and its nodes while it is in the list, so its state stays. It catches up with the updates that it missed when it comes back.
- The spacers are rows in a table and items in a list. In the children of a component, they take their tag from the element where the component inserts the children.
- Keys move between the items that are rendered. Focus that moves to the edge scrolls, and the window renders more.
A script in a block
A block body can start with a <script>. It runs for each instance of the body, such as for each item of a #for, and can declare signals and functions of its own:
The sample runs when it comes into view.
Each question has its own open. The script can read the item and the values of the component.
#repeat
#repeat (index of count) renders its body count times, with index from 0. #else renders when the count is 0:
The sample runs when it comes into view.
#switch
#switch renders the first #case whose condition is true, or #default:
The sample runs when it comes into view.
#key
#key (value) renders its body again when the value changes. The state inside the body starts over, such as the signals of a block script or of a component:
The sample runs when it comes into view.
Type a note, then switch: the field empties, because the body renders again for the new contact.
#template
#template name(parameters) declares a piece of markup that takes arguments. Call it in an expression:
The sample runs when it comes into view.
- A template can read the values of the component.
- Declare templates at the top level of the markup or at the start of a block body.
- A template can be passed as a prop, so a component renders your markup for its data. See Components.
#try and #catch
#try renders its body, and #catch renders instead if the body throws. #catch (error, reset) names the error and a function that renders the body again:
The sample runs when it comes into view.
- An error in a component inside the body is caught too.
- An error in the code of the body that runs in the browser is caught too. Both bodies ship when the body holds such code. See Errors in the browser.
- When the body throws on the server, nothing it rendered reaches the page: not its markup, the blocks inside it, or the state of its components. A component's stylesheet that only the body rendered is sent with the next copy of the component, such as one in
#catch. resetruns in the browser. If the body throws again,#catchrenders again.
#portal
#portal renders its body somewhere else in the page, such as a dialog at the end of the body. #portal (target) renders into an element or the element that a selector finds:
The sample runs when it comes into view.
- Without a target, the body goes to the end of the page.
- With a target, the body renders into it when the page loads in the browser. When the target changes, the body moves.
- The content of a portal is removed with the block that contains it, such as the
#ifabove.
#offscreen
#offscreen (visible) shows its body while visible is true. When it turns false, the body is hidden but stays in the page, with its elements and its state:
The sample runs when it comes into view.
Type a note, open the reply and come back: the note is still there.
- A body that is hidden when the page renders is not rendered. The browser renders it the first time it shows, and keeps it after.
- Each element at the top level of a hidden body gets an inline
display: none !important, which a class such as.paneldoes not override. Text at the top level is emptied. The elements keep their own inlinedisplayfor when the body shows. - The markup still updates while it is hidden, so it is current when it shows.
- The
$effectand$clientcallbacks of the body run their cleanups when it hides, and do not run while it is hidden. When it shows, the ones that ran before, or whose values changed, run once with the current values. <window>and<document>listeners in the body do not run while it is hidden.- The content of a
#portalin the body hides with it. - A nested
#offscreenis hidden while any#offscreenaround it is hidden. - When the block itself is removed, such as by an
#ifaround it, its body is removed as other blocks are.
Use it for tabs, steps of a form, or panels that the user switches between. Use #if when the body should start over each time it shows.
#client
#client renders its body in the browser only. See #client blocks.
#loading
#loading shows a fallback while the values that its body reads load. See #loading.
#defer
#defer renders its body on the server later, in a request of its own. See #defer.
#head
#head renders its body into the <head> of the page. See #head.