🍡 mochi
← All demos

Shared Props

When two or more islands share the same props (as serialized by devalue), the props are deduplicated to avoid shipping the same payload two or more times in one page load.

Each group below renders the same component three times with the same props. In the SSR: you'll find three <script type="application/json"> blocks (one per group) and nine <mochi-hydratable-island props-ref="…"> tags pointing at them. Each shared block carries a data-shared marker; a lone island (like the source code viewer on this page) still gets its own block, just without that marker.

Group A — recipes

<SharedPropsCard /> · A
  • Boil water for tea
  • Steep matcha 90s
  • Whisk into oat milk
<SharedPropsCard /> · A
  • Boil water for tea
  • Steep matcha 90s
  • Whisk into oat milk
<SharedPropsCard /> · A
  • Boil water for tea
  • Steep matcha 90s
  • Whisk into oat milk

Group B — TODOs

<SharedPropsCard /> · B
  • Reply to design review
  • Bump devalue to 5.x
  • Triage prop-dedup PR
  • Push staging deploy
<SharedPropsCard /> · B
  • Reply to design review
  • Bump devalue to 5.x
  • Triage prop-dedup PR
  • Push staging deploy
<SharedPropsCard /> · B
  • Reply to design review
  • Bump devalue to 5.x
  • Triage prop-dedup PR
  • Push staging deploy

Group C — track

<SharedPropsCard /> · C
  • Distance: 5.4 km
  • Pace: 5:42 / km
  • HR avg: 152 bpm
<SharedPropsCard /> · C
  • Distance: 5.4 km
  • Pace: 5:42 / km
  • HR avg: 152 bpm
<SharedPropsCard /> · C
  • Distance: 5.4 km
  • Pace: 5:42 / km
  • HR avg: 152 bpm
<script lang="ts">
  import SharedPropsCard from './SharedPropsCard.svelte';
  import { files } from './files.ts';

  const sources = await loadSources(files);

  // Three distinct prop payloads. Each is reused across three cards in its
  // group, so the page renders nine hydratable islands but only three unique
  // serialized payloads — Mochi hoists each into a single
  // <script type="application/json"> block and points the islands at it.
  const groups = [
    {
      heading: 'Group A — recipes',
      props: {
        label: '<SharedPropsCard /> · A',
        theme: { bg: '#1d2a23', fg: '#e6f1ea', accent: '#7fc89a' },
        items: [
          { id: 1, text: 'Boil water for tea' },
          { id: 2, text: 'Steep matcha 90s' },
          { id: 3, text: 'Whisk into oat milk' },
        ],
      },
    },
    {
      heading: 'Group B — TODOs',
      props: {
        label: '<SharedPropsCard /> · B',
        theme: { bg: '#26221d', fg: '#f1ece3', accent: '#d8a55c' },
        items: [
          { id: 1, text: 'Reply to design review' },
          { id: 2, text: 'Bump devalue to 5.x' },
          { id: 3, text: 'Triage prop-dedup PR' },
          { id: 4, text: 'Push staging deploy' },
        ],
      },
    },
    {
      heading: 'Group C — track',
      props: {
        label: '<SharedPropsCard /> · C',
        theme: { bg: '#1f242c', fg: '#e6ecf5', accent: '#7fa8d8' },
        items: [
          { id: 1, text: 'Distance: 5.4 km' },
          { id: 2, text: 'Pace: 5:42 / km' },
          { id: 3, text: 'HR avg: 152 bpm' },
        ],
      },
    },
  ];
</script>

<p class="hint">
  Each group below renders the same component three times with the same props. In the SSR: you'll find <strong>three</strong>
  <code>&lt;script type="application/json"&gt;</code>
  blocks (one per group) and nine <code>&lt;mochi-hydratable-island props-ref="…"&gt;</code> tags pointing at them. Each shared block carries a <code>data-shared</code> marker; a lone
  island (like the source code viewer on this page) still gets its own block, just without that marker.
</p>

{#each groups as group (group.heading)}
  <section class="group">
    <h3>{group.heading}</h3>
    <div class="row">
      <SharedPropsCard mochi:hydrate {...group.props} />
      <SharedPropsCard mochi:hydrate {...group.props} />
      <SharedPropsCard mochi:hydrate {...group.props} />
    </div>
  </section>
{/each}
Styles
<style>
  .hint {
    margin: 0 0 1.5rem;
    color: var(--text-muted);
    font-size: 0.95rem;
    line-height: 1.55;
  }

  .hint code {
    font-family: var(--font-mono);
    background: var(--surface-muted);
    border: 1px solid var(--border);
    padding: 0.05em 0.3em;
    border-radius: 4px;
    font-size: 0.85em;
  }

  .group {
    margin-bottom: 2rem;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
  }

  .group h3 {
    margin: 0;
    font-family: var(--font-serif);
    font-size: 1.05rem;
    font-weight: 500;
    color: var(--text);
  }

  .row {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.75rem;
  }

  @media (max-width: 640px) {
    .row {
      grid-template-columns: 1fr;
    }
  }
</style>