Islands Architecture
Visle uses the Islands Architecture pattern. Your pages are rendered as static HTML on the server, and only the interactive parts — called "islands" — are hydrated on the client.
What Are Islands?
An island is a Vue component that needs to be interactive in the browser. The rest of the page remains static HTML with zero JavaScript.
To make a component an island, use the v-client directive in your template. Any Vue component can become an island. You can specify a hydration strategy after v-client: to control when the component is hydrated.
v-client:load
Hydrates the component immediately when the page loads:
<MyComponent v-client:load />v-client:visible
Defers hydration until the component enters the viewport, using IntersectionObserver:
<MyComponent v-client:visible />You can customize the rootMargin to start hydration before the component is fully visible:
<MyComponent v-client:visible="{ rootMargin: '100px' }" />This triggers hydration when the component is within 100px of the viewport.
v-client:idle
Defers hydration until the browser is idle, using requestIdleCallback:
<MyComponent v-client:idle />You can specify a maximum wait time with timeout. The following example forces hydration after 2 seconds:
<MyComponent v-client:idle="{ timeout: 2000 }" />If the browser does not support requestIdleCallback, hydration occurs after the window's load event.
v-client:media
Defers hydration until the specified media query matches. The following example hydrates when the browser width is 768px or less:
<MyComponent v-client:media="'(max-width: 768px)'" />Note that the value passed to the directive is a JavaScript string literal — wrapped in single quotes inside the double quotes.
Props
Props passed to island components must be serializable. The following values are supported:
- Strings, numbers, booleans,
null,undefined - Plain objects and arrays
DateRegExpMapandSetURLBigIntInfinity,-Infinity,NaN
Functions, symbols, custom class instances (non-built-in), and circular references are not supported and will throw an error.
<!-- OK -->
<ProductCard
v-client:load
:product="{
id: 1,
name: 'Shirt',
tags: new Set(['vue', 'visle']),
}"
></ProductCard>
<!-- Not supported: function prop -->
<ProductCard v-client:load :get-product="(id) => productStore.get(id)"></ProductCard>How It Works
Each island component gets its own JavaScript bundle. When the page loads:
- The server renders the full page as HTML, including the island's initial content
- Island components are wrapped in
<vue-island>custom elements - Based on the hydration strategy, the browser loads the island's JavaScript
- The island is hydrated on top of the server-rendered HTML, making it interactive
This approach minimizes the amount of JavaScript sent to the client — only the code for interactive components is loaded.