Mesa guide / Special elements
<mesa:boundary>
Show a placeholder while the async values its body reads are loading, and an error view if they fail or something inside throws.
<script>
let selectedState = 'CA'
let selectedCity = ''
const cities = await getCities(selectedState)
</script>
<mesa:boundary>
{#snippet pending()}<p>Loading cities...</p>{/snippet}
{#snippet failed(error, reset)}
<p>{error.message}</p>
<button onclick={reset}>Try again</button>
{/snippet}
<select bind:value={selectedCity}>
{#each cities as city}<option>{city}</option>{/each}
</select>
</mesa:boundary>
Awaiting a top-level const makes an async value. The
boundary renders pending while any it reads is in flight and failed if one
rejects.
It waits only on what its body reads
A body that reads no async value shows at once. A body that renders a snippet
defined elsewhere waits on every async value in the component, since those reads
are not in its subtree. To hold the whole template until something has loaded,
use <mesa:mounted>.
It also catches a throw
A throw while rendering inside the boundary, or in a derivation or $: effect
that feeds it, disposes the content and renders failed(error, reset) in its
place. reset builds the content again; nothing retries on its own. A throw in
an event handler or a timer is not caught. The nearest boundary above the throw
that has a failed snippet catches it.
The pending and failed snippets
<mesa:boundary> and <mesa:mounted> find pending and failed the same way,
in this order:
- Snippets written inside the element.
{#snippet pending()}and{#snippet failed(error, reset)}written anywhere in the template.- Nothing: a blank pending state, and a rejection is swallowed. A boundary with
no
faileddoes not catch a throw, so it goes on to the boundary above.
A boundary can wrap just the part of the page that needs data, and a component may have several.
Spec: VISION.md § 12.6 · RULE 40