🍡 mochi

SSR framework for Svelte 5 + Bun with islands-based selective hydration

Passing props to islands

Any component marked with mochi:hydrate, mochi:hydrate:visible, or mochi:defer becomes an island, and its props have to cross the SSR → client boundary. Mochi serializes them with devalue, which preserves richer types than JSON.stringify.

<!-- Parent runs only on the server -->
<script>
  const user = { name: 'Ada', id: 42 };
  const visitedAt = new Date();
  const tags = new Set(['svelte', 'bun']);
</script>

<!-- Child is the island; props travel via devalue -->
<UserCard mochi:hydrate {user} {visitedAt} {tags} />

How it works

  1. During SSR, devalue.stringify serializes the props object.
  2. The serialized string is placed on the <mochi-hydratable-island> custom element as a props attribute. When multiple islands on the same page share an identical payload, it’s hoisted into a shared <script type="application/json"> block and each island gets a props-ref pointer instead.
  3. In the browser, the custom element reads the attribute (or the referenced script block) and runs devalue.parse on it.
  4. The reconstructed props are passed to Svelte’s hydrate(...), and the island takes over.

For mochi:defer server islands the flow is similar, except props are HMAC-signed and passed as a query parameter to a per-island endpoint — see Server islands.

Supported types

  • Plain objects and arrays
  • Primitives: strings, numbers, booleans, null
  • Date, RegExp, Map, Set, URL, URLSearchParams
  • BigInt, typed arrays (Uint8Array, etc.)
  • undefined, Infinity, NaN, -0
  • Repeated and cyclic references (identity is preserved)

Not supported

  • Functions
  • Class instances (the constructor is lost — only own enumerable properties survive)
  • Symbol

If you need any of these, compute them after hydration or pass a plain-data representation that the island can rebuild from.